.
This commit is contained in:
parent
a8c72b1d64
commit
8ead5a62da
@ -46,19 +46,27 @@ export class Result<T, E extends Error = Error> {
|
||||
}
|
||||
|
||||
get data(): T {
|
||||
if (!this._isSuccess) {
|
||||
throw new Error("Cannot get value data from a failed result.");
|
||||
}
|
||||
return this._data as T;
|
||||
return this.getData();
|
||||
}
|
||||
|
||||
get error(): E {
|
||||
return this.getError();
|
||||
}
|
||||
|
||||
getError(): E {
|
||||
if (this._isSuccess) {
|
||||
throw new Error("Cannot get error from a successful result.");
|
||||
}
|
||||
return this._error as E;
|
||||
}
|
||||
|
||||
getData(): T {
|
||||
if (!this._isSuccess) {
|
||||
throw new Error("Cannot get value data from a failed result.");
|
||||
}
|
||||
return this._data as T;
|
||||
}
|
||||
|
||||
/**
|
||||
* 🔹 `getOrElse(defaultValue: T): T`
|
||||
* Si el `Result` es un `ok`, devuelve `data`, de lo contrario, devuelve `defaultValue`.
|
||||
|
||||
@ -1,35 +1,54 @@
|
||||
import { UniqueID } from "./value-objects/unique-id";
|
||||
import { UniqueID } from "./unique-id";
|
||||
|
||||
describe("UniqueID Value Object", () => {
|
||||
it("should generate a new UUID using generateNewID()", () => {
|
||||
const result = UniqueID.generateNewID();
|
||||
// Mock UUID generation to ensure predictable tests
|
||||
jest.mock("uuid", () => ({ v4: () => "123e4567-e89b-12d3-a456-426614174000" }));
|
||||
|
||||
describe("UniqueID", () => {
|
||||
test("should create a UniqueID with a valid UUID", () => {
|
||||
const id = "123e4567-e89b-12d3-a456-426614174000";
|
||||
const result = UniqueID.create(id);
|
||||
|
||||
expect(result.isSuccess).toBe(true);
|
||||
expect(result.data.getValue()).toMatch(
|
||||
/^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i
|
||||
);
|
||||
expect(result.data?.isDefined()).toBe(true);
|
||||
});
|
||||
|
||||
it("should return an error for an invalid UUID", () => {
|
||||
test("should fail to create UniqueID with an invalid UUID", () => {
|
||||
const result = UniqueID.create("invalid-uuid");
|
||||
|
||||
expect(result.isSuccess).toBe(true);
|
||||
expect(result.error.message).toBe("Invalid UUID format");
|
||||
expect(result.isFailure).toBe(true);
|
||||
});
|
||||
|
||||
it("should create a valid UniqueID from an existing UUID", () => {
|
||||
const validUUID = "550e8400-e29b-41d4-a716-446655440000";
|
||||
const result = UniqueID.create(validUUID);
|
||||
test("should create an undefined UniqueID when id is undefined and generateOnEmpty is false", () => {
|
||||
const result = UniqueID.create(undefined, false);
|
||||
|
||||
expect(result.isSuccess).toBe(true);
|
||||
expect(result.data.getValue()).toBe(validUUID);
|
||||
expect(result.data?.isDefined()).toBe(false);
|
||||
});
|
||||
|
||||
it("should correctly convert UniqueID to string", () => {
|
||||
const validUUID = "550e8400-e29b-41d4-a716-446655440000";
|
||||
const result = UniqueID.create(validUUID);
|
||||
test("should generate a new UUID when id is undefined and generateOnEmpty is true", () => {
|
||||
const result = UniqueID.create(undefined, true);
|
||||
|
||||
expect(result.isSuccess).toBe(true);
|
||||
expect(result.data.toString()).toBe(validUUID);
|
||||
expect(result.data?.isDefined()).toBe(true);
|
||||
});
|
||||
|
||||
test("should fail when id is null", () => {
|
||||
const result = UniqueID.create(null as any);
|
||||
|
||||
expect(result.isFailure).toBe(true);
|
||||
});
|
||||
|
||||
test("should create a UniqueID when id is an empty string and generateOnEmpty is true", () => {
|
||||
const result = UniqueID.create(" ", true);
|
||||
|
||||
expect(result.isSuccess).toBe(true);
|
||||
expect(result.data?.isDefined()).toBe(true);
|
||||
});
|
||||
|
||||
test("should create an undefined UniqueID when id is an empty string and generateOnEmpty is false", () => {
|
||||
const result = UniqueID.create(" ", false);
|
||||
|
||||
expect(result.isSuccess).toBe(true);
|
||||
expect(result.data?.isDefined()).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
@ -3,17 +3,27 @@ import { z } from "zod";
|
||||
import { Result } from "../result";
|
||||
import { ValueObject } from "./value-object";
|
||||
|
||||
const UUIDSchema = z.string().uuid({ message: "Invalid UUID format" });
|
||||
export const UNDEFINED_ID = undefined;
|
||||
|
||||
export class UniqueID extends ValueObject<string | undefined> {
|
||||
protected readonly _hasId!: boolean;
|
||||
|
||||
protected constructor(id?: string) {
|
||||
super(id);
|
||||
this._hasId = id != UNDEFINED_ID;
|
||||
}
|
||||
|
||||
export class UniqueID extends ValueObject<string> {
|
||||
static create(id?: string, generateOnEmpty: boolean = false): Result<UniqueID, Error> {
|
||||
if (!id) {
|
||||
return generateOnEmpty
|
||||
? UniqueID.generateNewID()
|
||||
: Result.fail(new Error("ID is null or empty"));
|
||||
if (id === null) {
|
||||
return Result.fail(new Error("ID cannot be null"));
|
||||
}
|
||||
|
||||
const result = UniqueID.validate(id.trim());
|
||||
const trimmedId = id?.trim();
|
||||
if (!trimmedId) {
|
||||
return generateOnEmpty ? UniqueID.generateNewID() : Result.ok(new UniqueID(UNDEFINED_ID));
|
||||
}
|
||||
|
||||
const result = UniqueID.validate(trimmedId);
|
||||
|
||||
return result.success
|
||||
? Result.ok(new UniqueID(result.data))
|
||||
@ -32,4 +42,12 @@ export class UniqueID extends ValueObject<string> {
|
||||
static generateNewID(): Result<UniqueID, never> {
|
||||
return Result.ok(new UniqueID(uuidv4()));
|
||||
}
|
||||
|
||||
static generateUndefinedID(): Result<UniqueID, never> {
|
||||
return Result.ok(new UniqueID(UNDEFINED_ID));
|
||||
}
|
||||
|
||||
isDefined(): boolean {
|
||||
return this._hasId;
|
||||
}
|
||||
}
|
||||
|
||||
@ -5,8 +5,6 @@ export abstract class ValueObject<T> {
|
||||
|
||||
protected constructor(value: T) {
|
||||
this._value = typeof value === "object" && value !== null ? Object.freeze(value) : value;
|
||||
|
||||
Object.freeze(this);
|
||||
}
|
||||
|
||||
equals(other: ValueObject<T>): boolean {
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { Result } from "@common/domain";
|
||||
import { Result, UniqueID } from "@common/domain";
|
||||
import { AuthenticatedUser, EmailAddress, PasswordHash, Username } from "../domain";
|
||||
|
||||
export interface IAuthService {
|
||||
@ -8,8 +8,16 @@ export interface IAuthService {
|
||||
passwordHash: PasswordHash;
|
||||
}): Promise<Result<AuthenticatedUser, Error>>;
|
||||
|
||||
loginUser(params: {
|
||||
email: EmailAddress;
|
||||
passwordHash: PasswordHash;
|
||||
}): Promise<Result<AuthenticatedUser, Error>>;
|
||||
loginUser(params: { email: EmailAddress; passwordHash: PasswordHash; tabId: UniqueID }): Promise<
|
||||
Result<
|
||||
{
|
||||
user: AuthenticatedUser;
|
||||
tokens: {
|
||||
accessToken: string;
|
||||
refreshToken: string;
|
||||
};
|
||||
},
|
||||
Error
|
||||
>
|
||||
>;
|
||||
}
|
||||
|
||||
@ -5,22 +5,27 @@ import {
|
||||
EmailAddress,
|
||||
IAuthenticatedUserRepository,
|
||||
PasswordHash,
|
||||
TabContext,
|
||||
Username,
|
||||
} from "@contexts/auth/domain";
|
||||
} from "../domain";
|
||||
import { ITabContextRepository } from "../domain/repositories/tab-context-repository.interface";
|
||||
import { IAuthProvider } from "./auth-provider.interface";
|
||||
import { IAuthService } from "./auth-service.interface";
|
||||
|
||||
export class AuthService implements IAuthService {
|
||||
private readonly _respository!: IAuthenticatedUserRepository;
|
||||
private readonly _userRepo!: IAuthenticatedUserRepository;
|
||||
private readonly _tabContactRepo!: ITabContextRepository;
|
||||
private readonly _transactionManager!: ITransactionManager;
|
||||
private readonly _authProvider: IAuthProvider;
|
||||
|
||||
constructor(
|
||||
repository: IAuthenticatedUserRepository,
|
||||
userRepo: IAuthenticatedUserRepository,
|
||||
tabContextRepo: ITabContextRepository,
|
||||
transactionManager: ITransactionManager,
|
||||
authProvider: IAuthProvider
|
||||
) {
|
||||
this._respository = repository;
|
||||
this._userRepo = userRepo;
|
||||
this._tabContactRepo = tabContextRepo;
|
||||
this._transactionManager = transactionManager;
|
||||
this._authProvider = authProvider;
|
||||
}
|
||||
@ -39,7 +44,7 @@ export class AuthService implements IAuthService {
|
||||
const { username, email, passwordHash } = params;
|
||||
|
||||
// Verificar si el usuario ya existe
|
||||
const userExists = await this._respository.findUserByEmail(email, transaction);
|
||||
const userExists = await this._userRepo.findUserByEmail(email, transaction);
|
||||
if (userExists.isSuccess && userExists.data) {
|
||||
return Result.fail(new Error("Email is already registered"));
|
||||
}
|
||||
@ -64,7 +69,7 @@ export class AuthService implements IAuthService {
|
||||
return Result.fail(userOrError.error);
|
||||
}
|
||||
|
||||
const createdResult = await this._respository.createUser(userOrError.data, transaction);
|
||||
const createdResult = await this._userRepo.createUser(userOrError.data, transaction);
|
||||
|
||||
if (createdResult.isFailure) {
|
||||
return Result.fail(createdResult.error);
|
||||
@ -84,21 +89,35 @@ export class AuthService implements IAuthService {
|
||||
async loginUser(params: {
|
||||
email: EmailAddress;
|
||||
passwordHash: PasswordHash;
|
||||
}): Promise<Result<AuthenticatedUser, Error>> {
|
||||
tabId: UniqueID;
|
||||
}): Promise<
|
||||
Result<
|
||||
{
|
||||
user: AuthenticatedUser;
|
||||
tokens: {
|
||||
accessToken: string;
|
||||
refreshToken: string;
|
||||
};
|
||||
},
|
||||
Error
|
||||
>
|
||||
> {
|
||||
try {
|
||||
return await this._transactionManager.complete(async (transaction) => {
|
||||
const { email, passwordHash } = params;
|
||||
const { email, passwordHash, tabId } = params;
|
||||
|
||||
// Verificar que el tab ID está definido
|
||||
if (!tabId.isDefined()) {
|
||||
return Result.fail(new Error("Invalid tab id"));
|
||||
}
|
||||
|
||||
// 🔹 Verificar si el usuario existe en la base de datos
|
||||
const userResult = await this._respository.findUserByEmail(email, transaction);
|
||||
const userResult = await this._userRepo.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);
|
||||
@ -106,56 +125,42 @@ export class AuthService implements IAuthService {
|
||||
return Result.fail(new Error("Invalid email or password"));
|
||||
}
|
||||
|
||||
// Registrar o actualizar el contexto de ese tab ID
|
||||
const contextOrError = TabContext.create({
|
||||
userId: user.id,
|
||||
tabId: tabId,
|
||||
companyId: UniqueID.generateUndefinedID().data,
|
||||
branchId: UniqueID.generateUndefinedID().data,
|
||||
});
|
||||
|
||||
if (contextOrError.isFailure) {
|
||||
return Result.fail(new Error("Error creating user context"));
|
||||
}
|
||||
|
||||
await this._tabContactRepo.registerContext(contextOrError.data, transaction);
|
||||
|
||||
// 🔹 Generar Access Token y Refresh Token
|
||||
user.accessToken = this._authProvider.generateAccessToken({
|
||||
const accessToken = this._authProvider.generateAccessToken({
|
||||
userId: user.id.toString(),
|
||||
email: email.toString(),
|
||||
tabId: tabId.toString(),
|
||||
roles: ["USER"],
|
||||
});
|
||||
|
||||
user.refreshToken = this._authProvider.generateRefreshToken({
|
||||
const refreshToken = this._authProvider.generateRefreshToken({
|
||||
userId: user.id.toString(),
|
||||
});
|
||||
|
||||
return Result.ok(user);
|
||||
return Result.ok({
|
||||
user,
|
||||
tokens: {
|
||||
accessToken,
|
||||
refreshToken,
|
||||
},
|
||||
});
|
||||
});
|
||||
} 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<Result<{ message: string }, Error>> {
|
||||
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" });
|
||||
}*/
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import { createSequelizeTransactionManager } from "@common/infrastructure";
|
||||
|
||||
import { createAuthenticatedUserRepository } from "../infraestructure";
|
||||
import { createAuthenticatedUserRepository, createTabContextRepository } from "../infraestructure";
|
||||
import { createPassportAuthProvider } from "../infraestructure/passport/passport-auth-provider";
|
||||
import { IAuthProvider } from "./auth-provider.interface";
|
||||
import { IAuthService } from "./auth-service.interface";
|
||||
@ -12,10 +12,16 @@ export * from "./auth-service.interface";
|
||||
export const createAuthService = (): IAuthService => {
|
||||
const transactionManager = createSequelizeTransactionManager();
|
||||
const authenticatedUserRepository = createAuthenticatedUserRepository();
|
||||
const tabContextRepository = createTabContextRepository();
|
||||
|
||||
const authProvider: IAuthProvider = createPassportAuthProvider(
|
||||
authenticatedUserRepository,
|
||||
transactionManager
|
||||
);
|
||||
return new AuthService(authenticatedUserRepository, transactionManager, authProvider);
|
||||
return new AuthService(
|
||||
authenticatedUserRepository,
|
||||
tabContextRepository,
|
||||
transactionManager,
|
||||
authProvider
|
||||
);
|
||||
};
|
||||
|
||||
@ -3,7 +3,12 @@ import { TabContext } from "../domain";
|
||||
|
||||
export interface ITabContextService {
|
||||
getByTabId(tabId: UniqueID): Promise<Result<TabContext, Error>>;
|
||||
createContext(tabId: UniqueID, userId: UniqueID): Promise<Result<TabContext, Error>>;
|
||||
createContext(params: {
|
||||
tabId: UniqueID;
|
||||
userId: UniqueID;
|
||||
companyId: UniqueID;
|
||||
branchId: UniqueID;
|
||||
}): Promise<Result<TabContext, Error>>;
|
||||
assignCompany(tabId: UniqueID, companyId: UniqueID): Promise<Result<void, Error>>;
|
||||
removeContext(tabId: UniqueID): Promise<Result<void, Error>>;
|
||||
}
|
||||
|
||||
@ -39,7 +39,14 @@ export class TabContextService implements ITabContextService {
|
||||
/**
|
||||
* Registra un nuevo contexto de pestaña para un usuario
|
||||
*/
|
||||
async createContext(tabId: UniqueID, userId: UniqueID): Promise<Result<TabContext, Error>> {
|
||||
async createContext(params: {
|
||||
tabId: UniqueID;
|
||||
userId: UniqueID;
|
||||
companyId: UniqueID;
|
||||
branchId: UniqueID;
|
||||
}): Promise<Result<TabContext, Error>> {
|
||||
const { tabId, userId, companyId, branchId } = params;
|
||||
|
||||
if (!userId || !tabId) {
|
||||
return Result.fail(new Error("User ID and Tab ID are required"));
|
||||
}
|
||||
@ -50,6 +57,8 @@ export class TabContextService implements ITabContextService {
|
||||
{
|
||||
userId,
|
||||
tabId,
|
||||
companyId,
|
||||
branchId,
|
||||
},
|
||||
UniqueID.generateNewID().data
|
||||
);
|
||||
@ -58,7 +67,7 @@ export class TabContextService implements ITabContextService {
|
||||
return Result.fail(contextOrError.error);
|
||||
}
|
||||
|
||||
await this._respository.createContext(contextOrError.data, transaction);
|
||||
await this._respository.registerContext(contextOrError.data, transaction);
|
||||
|
||||
return Result.ok(contextOrError.data);
|
||||
});
|
||||
|
||||
@ -3,38 +3,27 @@ import { DomainEntity, Result, UniqueID } from "@common/domain";
|
||||
export interface ITabContextProps {
|
||||
tabId: UniqueID;
|
||||
userId: UniqueID;
|
||||
companyId?: UniqueID;
|
||||
branchId?: UniqueID;
|
||||
companyId: UniqueID;
|
||||
branchId: UniqueID;
|
||||
}
|
||||
|
||||
export interface ITabContext {
|
||||
tabId: UniqueID;
|
||||
userId: UniqueID;
|
||||
companyId?: UniqueID;
|
||||
branchId?: UniqueID;
|
||||
companyId: UniqueID;
|
||||
branchId: UniqueID;
|
||||
|
||||
assignCompany(companyId: UniqueID): void;
|
||||
assignBranch(branchId: UniqueID): void;
|
||||
hasCompanyAssigned(): boolean;
|
||||
hasBranchAssigned(): boolean;
|
||||
|
||||
toPersistenceData(): any;
|
||||
}
|
||||
|
||||
export class TabContext extends DomainEntity<ITabContextProps> implements ITabContext {
|
||||
private _companyId: UniqueID | undefined;
|
||||
private _branchId: UniqueID | undefined;
|
||||
|
||||
static create(props: ITabContextProps, id?: UniqueID): Result<TabContext, Error> {
|
||||
return Result.ok(new this(props, id));
|
||||
}
|
||||
|
||||
protected constructor(props: ITabContextProps, id?: UniqueID) {
|
||||
const { tabId, userId, companyId, branchId } = props;
|
||||
|
||||
super({ tabId, userId }, id);
|
||||
this._companyId = companyId;
|
||||
this._branchId = branchId;
|
||||
}
|
||||
|
||||
get tabId(): UniqueID {
|
||||
return this._props.tabId;
|
||||
}
|
||||
@ -43,28 +32,20 @@ export class TabContext extends DomainEntity<ITabContextProps> implements ITabCo
|
||||
return this._props.userId;
|
||||
}
|
||||
|
||||
get companyId(): UniqueID | undefined {
|
||||
return this._companyId;
|
||||
get companyId(): UniqueID {
|
||||
return this._props.companyId;
|
||||
}
|
||||
|
||||
get branchId(): UniqueID | undefined {
|
||||
return this._branchId;
|
||||
get branchId(): UniqueID {
|
||||
return this._props.branchId;
|
||||
}
|
||||
|
||||
hasCompanyAssigned(): boolean {
|
||||
return this._companyId !== undefined;
|
||||
}
|
||||
|
||||
assignCompany(companyId: UniqueID): void {
|
||||
this._companyId = companyId;
|
||||
return this._props.companyId.isDefined();
|
||||
}
|
||||
|
||||
hasBranchAssigned(): boolean {
|
||||
return this._branchId !== undefined;
|
||||
}
|
||||
|
||||
assignBranch(branchId: UniqueID): void {
|
||||
this._branchId = branchId;
|
||||
return this._props.branchId.isDefined();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -74,8 +55,8 @@ export class TabContext extends DomainEntity<ITabContextProps> implements ITabCo
|
||||
return {
|
||||
id: this._id.toString(),
|
||||
user_id: this.userId.toString(),
|
||||
company_id: this._companyId ? this._companyId.toString() : undefined,
|
||||
branchId: this._branchId ? this._branchId.toString() : undefined,
|
||||
company_id: this.companyId.toString(),
|
||||
branchId: this.branchId.toString(),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@ -4,7 +4,7 @@ import { TabContext } from "../entities";
|
||||
|
||||
export interface ITabContextRepository {
|
||||
getContextByTabId(tabId: UniqueID, transaction?: any): Promise<Result<TabContext, Error>>;
|
||||
createContext(context: TabContext, transaction?: Transaction): Promise<Result<void, Error>>;
|
||||
registerContext(context: TabContext, transaction?: Transaction): Promise<Result<void, Error>>;
|
||||
contextExists(tabId: UniqueID, transaction?: any): Promise<Result<boolean, Error>>;
|
||||
updateCompanyByTabId(
|
||||
tabId: UniqueID,
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { Result, UniqueID } from "@common/domain";
|
||||
import { EmailAddress, PasswordHash, TabContext, Username } from "@contexts/auth/domain";
|
||||
import { TabContext } from "@contexts/auth/domain";
|
||||
import { ITabContextMapper } from "./tab-context-mapper.interface";
|
||||
|
||||
export class TabContextMapper implements ITabContextMapper {
|
||||
@ -10,16 +10,18 @@ export class TabContextMapper implements ITabContextMapper {
|
||||
|
||||
// Crear Value Objects asegurando que sean válidos
|
||||
const uniqueIdResult = UniqueID.create(entity.id);
|
||||
const userIdResult = Username.create(entity.user_id);
|
||||
const companyIdResult = PasswordHash.create(entity.passwordHash);
|
||||
const brachIdResult = EmailAddress.create(entity.email);
|
||||
const tabIdResult = UniqueID.create(entity.tab_id);
|
||||
const userIdResult = UniqueID.create(entity.user_id);
|
||||
const companyIdResult = UniqueID.create(entity.company_id, false);
|
||||
const brachIdResult = UniqueID.create(entity.branch_id, false);
|
||||
|
||||
// Validar que no haya errores en la creación de los Value Objects
|
||||
const okOrError = Result.combine([
|
||||
uniqueIdResult,
|
||||
usernameResult,
|
||||
tabIdResult,
|
||||
userIdResult,
|
||||
companyIdResult,
|
||||
emailResult,
|
||||
brachIdResult,
|
||||
]);
|
||||
if (okOrError.isFailure) {
|
||||
return Result.fail(okOrError.error.message);
|
||||
@ -28,11 +30,10 @@ export class TabContextMapper implements ITabContextMapper {
|
||||
// Crear el agregado de dominio
|
||||
return TabContext.create(
|
||||
{
|
||||
username: usernameResult.data!,
|
||||
email: emailResult.data!,
|
||||
passwordHash: companyIdResult.data!,
|
||||
roles: entity.roles || [],
|
||||
token: entity.token,
|
||||
tabId: tabIdResult.data!,
|
||||
userId: userIdResult.data!,
|
||||
companyId: companyIdResult.data,
|
||||
branchId: brachIdResult.data,
|
||||
},
|
||||
uniqueIdResult.data!
|
||||
);
|
||||
|
||||
@ -3,7 +3,7 @@ import { SequelizeRepository } from "@common/infrastructure";
|
||||
import { TabContext } from "@contexts/auth/domain/";
|
||||
import { ITabContextRepository } from "@contexts/auth/domain/repositories/tab-context-repository.interface";
|
||||
import { Transaction } from "sequelize";
|
||||
import { ITabContextMapper } from "../mappers";
|
||||
import { createTabContextMapper, ITabContextMapper } from "../mappers";
|
||||
import { TabContextModel } from "./tab-context.model";
|
||||
|
||||
export class TabContextRepository
|
||||
@ -66,23 +66,22 @@ export class TabContextRepository
|
||||
}
|
||||
}
|
||||
|
||||
async createContext(
|
||||
/**
|
||||
* Crea un contexto para un tab id o actualiza si ya existe
|
||||
* @param context
|
||||
* @param transaction
|
||||
* @returns
|
||||
*/
|
||||
|
||||
async registerContext(
|
||||
context: TabContext,
|
||||
transaction?: Transaction
|
||||
): Promise<Result<void, Error>> {
|
||||
try {
|
||||
const { id } = context;
|
||||
const persistenceData = this._mapper.toPersistence(context);
|
||||
await TabContextModel.create(
|
||||
{
|
||||
...persistenceData,
|
||||
id: id.toString(),
|
||||
},
|
||||
{
|
||||
include: [{ all: true }],
|
||||
transaction,
|
||||
}
|
||||
);
|
||||
|
||||
await this._save(TabContextModel, id, persistenceData, {}, transaction);
|
||||
return Result.ok();
|
||||
} catch (error: any) {
|
||||
return this._handleDatabaseError(error, this._customErrorMapper);
|
||||
@ -126,3 +125,8 @@ export class TabContextRepository
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const createTabContextRepository = (): ITabContextRepository => {
|
||||
const tabContextMapper = createTabContextMapper();
|
||||
return new TabContextRepository(tabContextMapper);
|
||||
};
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import { UniqueID } from "@common/domain";
|
||||
import { ExpressController } from "@common/presentation";
|
||||
import { createAuthService, IAuthService } from "@contexts/auth/application";
|
||||
import { EmailAddress, PasswordHash } from "@contexts/auth/domain";
|
||||
@ -14,16 +15,19 @@ class LoginController extends ExpressController {
|
||||
}
|
||||
|
||||
async executeImpl() {
|
||||
const tabId = this.req.headers["x-tab-id"];
|
||||
const emailVO = EmailAddress.create(this.req.body.email);
|
||||
const passwordHashVO = PasswordHash.create(this.req.body.password);
|
||||
const tabIdVO = UniqueID.create(String(tabId));
|
||||
|
||||
if ([emailVO, passwordHashVO].some((r) => r.isFailure)) {
|
||||
if ([emailVO, passwordHashVO, tabIdVO].some((r) => r.isFailure)) {
|
||||
return this.clientError("Invalid input data");
|
||||
}
|
||||
|
||||
const userOrError = await this._authService.loginUser({
|
||||
email: emailVO.data,
|
||||
passwordHash: passwordHashVO.data,
|
||||
tabId: tabIdVO.data,
|
||||
});
|
||||
|
||||
if (userOrError.isFailure) {
|
||||
|
||||
@ -2,20 +2,40 @@ import { AuthenticatedUser } from "@contexts/auth/domain";
|
||||
import { ILoginUserResponseDTO } from "../../dto";
|
||||
|
||||
export interface ILoginPresenter {
|
||||
map: (user: AuthenticatedUser) => ILoginUserResponseDTO;
|
||||
map: (data: {
|
||||
user: AuthenticatedUser;
|
||||
tokens: {
|
||||
accessToken: string;
|
||||
refreshToken: string;
|
||||
};
|
||||
}) => ILoginUserResponseDTO;
|
||||
}
|
||||
|
||||
export const LoginPresenter: ILoginPresenter = {
|
||||
map: (user: AuthenticatedUser): ILoginUserResponseDTO => {
|
||||
//const { user, token, refreshToken } = loginUser;
|
||||
//const roles = user.getRoles()?.map((rol) => rol.toString()) || [];
|
||||
map: (data: {
|
||||
user: AuthenticatedUser;
|
||||
tokens: {
|
||||
accessToken: string;
|
||||
refreshToken: string;
|
||||
};
|
||||
}): ILoginUserResponseDTO => {
|
||||
const {
|
||||
user,
|
||||
tokens: { accessToken, refreshToken },
|
||||
} = data;
|
||||
|
||||
const userData = user.toPersistenceData();
|
||||
|
||||
return {
|
||||
user_id: userData,
|
||||
access_token: userData.accessToken,
|
||||
refresh_token: userData.refreshToken,
|
||||
user: {
|
||||
id: userData.id,
|
||||
email: userData.email,
|
||||
username: userData.username,
|
||||
},
|
||||
tokens: {
|
||||
access_token: accessToken,
|
||||
refresh_token: refreshToken,
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
@ -5,14 +5,16 @@ export interface IRegisterUserResponseDTO {
|
||||
}
|
||||
|
||||
export interface ILoginUserResponseDTO {
|
||||
access_token: string;
|
||||
refresh_token: string;
|
||||
user: {
|
||||
id: string;
|
||||
username: string;
|
||||
email: string;
|
||||
};
|
||||
tab_id: string;
|
||||
tokens: {
|
||||
access_token: string;
|
||||
refresh_token: string;
|
||||
};
|
||||
//tab_id: string;
|
||||
}
|
||||
|
||||
export interface ILogoutResponseDTO {
|
||||
|
||||
@ -32,7 +32,7 @@ export const validateTabContext = async (req: Request, res: Response, next: Next
|
||||
);
|
||||
}
|
||||
|
||||
const contextOrError = await TabContextRepository.getByTabId(tabId);
|
||||
const contextOrError = await TabContextRepository.getContextByTabId(tabId);
|
||||
if (contextOrError.isFailure) {
|
||||
return ExpressController.errorResponse(
|
||||
new ApiError({
|
||||
|
||||
@ -1,9 +1,7 @@
|
||||
import { validateRequest } from "@common/presentation";
|
||||
import { validateTabHeader } from "@contexts/auth/presentation";
|
||||
import {
|
||||
createLoginController,
|
||||
createRegisterController,
|
||||
} from "@contexts/auth/presentation/controllers";
|
||||
import { createLoginController } from "@contexts/auth/presentation/controllers";
|
||||
import { createRegisterController } from "@contexts/auth/presentation/controllers/register/register.controller";
|
||||
import { LoginUserSchema, RegisterUserSchema } from "@contexts/auth/presentation/dto";
|
||||
import { Router } from "express";
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user