From 8ead5a62da7c1195c5c1126e81e7a05724f510f0 Mon Sep 17 00:00:00 2001 From: david Date: Tue, 4 Feb 2025 19:25:10 +0100 Subject: [PATCH] . --- apps/server/src/common/domain/result.ts | 16 ++- .../domain/value-objects/unique-id.spec.ts | 55 ++++++--- .../common/domain/value-objects/unique-id.ts | 32 ++++-- .../domain/value-objects/value-object.ts | 2 - .../application/auth-service.interface.ts | 18 ++- .../contexts/auth/application/auth.service.ts | 105 +++++++++--------- .../src/contexts/auth/application/index.ts | 10 +- .../tab-context-service.interface.ts | 7 +- .../auth/application/tab-context.service.ts | 13 ++- .../auth/domain/entities/tab-context.ts | 47 +++----- .../tab-context-repository.interface.ts | 2 +- .../mappers/tab-context.mapper.ts | 23 ++-- .../sequelize/tab-context.repository.ts | 28 +++-- .../controllers/login/login.controller.ts | 6 +- .../controllers/login/login.presenter.ts | 34 ++++-- .../presentation/dto/auth.response.dto.ts | 8 +- .../middleware/tab-context.middleware.ts | 2 +- apps/server/src/routes/auth.routes.ts | 6 +- 18 files changed, 250 insertions(+), 164 deletions(-) diff --git a/apps/server/src/common/domain/result.ts b/apps/server/src/common/domain/result.ts index 6edcdc69..f95b5a8f 100644 --- a/apps/server/src/common/domain/result.ts +++ b/apps/server/src/common/domain/result.ts @@ -46,19 +46,27 @@ export class Result { } 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`. diff --git a/apps/server/src/common/domain/value-objects/unique-id.spec.ts b/apps/server/src/common/domain/value-objects/unique-id.spec.ts index 9e472d66..96393e7f 100644 --- a/apps/server/src/common/domain/value-objects/unique-id.spec.ts +++ b/apps/server/src/common/domain/value-objects/unique-id.spec.ts @@ -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); }); }); diff --git a/apps/server/src/common/domain/value-objects/unique-id.ts b/apps/server/src/common/domain/value-objects/unique-id.ts index 2f5797a2..4e2d3785 100644 --- a/apps/server/src/common/domain/value-objects/unique-id.ts +++ b/apps/server/src/common/domain/value-objects/unique-id.ts @@ -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 { + protected readonly _hasId!: boolean; + + protected constructor(id?: string) { + super(id); + this._hasId = id != UNDEFINED_ID; + } -export class UniqueID extends ValueObject { static create(id?: string, generateOnEmpty: boolean = false): Result { - 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 { static generateNewID(): Result { return Result.ok(new UniqueID(uuidv4())); } + + static generateUndefinedID(): Result { + return Result.ok(new UniqueID(UNDEFINED_ID)); + } + + isDefined(): boolean { + return this._hasId; + } } diff --git a/apps/server/src/common/domain/value-objects/value-object.ts b/apps/server/src/common/domain/value-objects/value-object.ts index 95ed02d6..782899f4 100644 --- a/apps/server/src/common/domain/value-objects/value-object.ts +++ b/apps/server/src/common/domain/value-objects/value-object.ts @@ -5,8 +5,6 @@ export abstract class ValueObject { protected constructor(value: T) { this._value = typeof value === "object" && value !== null ? Object.freeze(value) : value; - - Object.freeze(this); } equals(other: ValueObject): boolean { diff --git a/apps/server/src/contexts/auth/application/auth-service.interface.ts b/apps/server/src/contexts/auth/application/auth-service.interface.ts index b183f850..0e8feed0 100644 --- a/apps/server/src/contexts/auth/application/auth-service.interface.ts +++ b/apps/server/src/contexts/auth/application/auth-service.interface.ts @@ -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>; - loginUser(params: { - email: EmailAddress; - passwordHash: PasswordHash; - }): Promise>; + loginUser(params: { email: EmailAddress; passwordHash: PasswordHash; tabId: UniqueID }): Promise< + Result< + { + user: AuthenticatedUser; + tokens: { + accessToken: string; + refreshToken: string; + }; + }, + Error + > + >; } diff --git a/apps/server/src/contexts/auth/application/auth.service.ts b/apps/server/src/contexts/auth/application/auth.service.ts index 40050b34..d393de26 100644 --- a/apps/server/src/contexts/auth/application/auth.service.ts +++ b/apps/server/src/contexts/auth/application/auth.service.ts @@ -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> { + 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> { - 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" }); - }*/ } diff --git a/apps/server/src/contexts/auth/application/index.ts b/apps/server/src/contexts/auth/application/index.ts index ae075f28..57e9e7de 100644 --- a/apps/server/src/contexts/auth/application/index.ts +++ b/apps/server/src/contexts/auth/application/index.ts @@ -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 + ); }; diff --git a/apps/server/src/contexts/auth/application/tab-context-service.interface.ts b/apps/server/src/contexts/auth/application/tab-context-service.interface.ts index 77683367..bbd6f6bb 100644 --- a/apps/server/src/contexts/auth/application/tab-context-service.interface.ts +++ b/apps/server/src/contexts/auth/application/tab-context-service.interface.ts @@ -3,7 +3,12 @@ import { TabContext } from "../domain"; export interface ITabContextService { getByTabId(tabId: UniqueID): Promise>; - createContext(tabId: UniqueID, userId: UniqueID): Promise>; + createContext(params: { + tabId: UniqueID; + userId: UniqueID; + companyId: UniqueID; + branchId: UniqueID; + }): Promise>; assignCompany(tabId: UniqueID, companyId: UniqueID): Promise>; removeContext(tabId: UniqueID): Promise>; } diff --git a/apps/server/src/contexts/auth/application/tab-context.service.ts b/apps/server/src/contexts/auth/application/tab-context.service.ts index b85c56b0..34fdeb60 100644 --- a/apps/server/src/contexts/auth/application/tab-context.service.ts +++ b/apps/server/src/contexts/auth/application/tab-context.service.ts @@ -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> { + async createContext(params: { + tabId: UniqueID; + userId: UniqueID; + companyId: UniqueID; + branchId: UniqueID; + }): Promise> { + 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); }); diff --git a/apps/server/src/contexts/auth/domain/entities/tab-context.ts b/apps/server/src/contexts/auth/domain/entities/tab-context.ts index 773217c1..103d332c 100644 --- a/apps/server/src/contexts/auth/domain/entities/tab-context.ts +++ b/apps/server/src/contexts/auth/domain/entities/tab-context.ts @@ -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 implements ITabContext { - private _companyId: UniqueID | undefined; - private _branchId: UniqueID | undefined; - static create(props: ITabContextProps, id?: UniqueID): Result { 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 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 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(), }; } } diff --git a/apps/server/src/contexts/auth/domain/repositories/tab-context-repository.interface.ts b/apps/server/src/contexts/auth/domain/repositories/tab-context-repository.interface.ts index 79b9e225..13ddaeef 100644 --- a/apps/server/src/contexts/auth/domain/repositories/tab-context-repository.interface.ts +++ b/apps/server/src/contexts/auth/domain/repositories/tab-context-repository.interface.ts @@ -4,7 +4,7 @@ import { TabContext } from "../entities"; export interface ITabContextRepository { getContextByTabId(tabId: UniqueID, transaction?: any): Promise>; - createContext(context: TabContext, transaction?: Transaction): Promise>; + registerContext(context: TabContext, transaction?: Transaction): Promise>; contextExists(tabId: UniqueID, transaction?: any): Promise>; updateCompanyByTabId( tabId: UniqueID, diff --git a/apps/server/src/contexts/auth/infraestructure/mappers/tab-context.mapper.ts b/apps/server/src/contexts/auth/infraestructure/mappers/tab-context.mapper.ts index 680889b2..ff66c8d5 100644 --- a/apps/server/src/contexts/auth/infraestructure/mappers/tab-context.mapper.ts +++ b/apps/server/src/contexts/auth/infraestructure/mappers/tab-context.mapper.ts @@ -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! ); diff --git a/apps/server/src/contexts/auth/infraestructure/sequelize/tab-context.repository.ts b/apps/server/src/contexts/auth/infraestructure/sequelize/tab-context.repository.ts index 616975a9..baaf32bd 100644 --- a/apps/server/src/contexts/auth/infraestructure/sequelize/tab-context.repository.ts +++ b/apps/server/src/contexts/auth/infraestructure/sequelize/tab-context.repository.ts @@ -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> { 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); +}; diff --git a/apps/server/src/contexts/auth/presentation/controllers/login/login.controller.ts b/apps/server/src/contexts/auth/presentation/controllers/login/login.controller.ts index c7c571b7..94e68c18 100644 --- a/apps/server/src/contexts/auth/presentation/controllers/login/login.controller.ts +++ b/apps/server/src/contexts/auth/presentation/controllers/login/login.controller.ts @@ -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) { diff --git a/apps/server/src/contexts/auth/presentation/controllers/login/login.presenter.ts b/apps/server/src/contexts/auth/presentation/controllers/login/login.presenter.ts index 056a15a5..39ee1a48 100644 --- a/apps/server/src/contexts/auth/presentation/controllers/login/login.presenter.ts +++ b/apps/server/src/contexts/auth/presentation/controllers/login/login.presenter.ts @@ -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, + }, }; }, }; diff --git a/apps/server/src/contexts/auth/presentation/dto/auth.response.dto.ts b/apps/server/src/contexts/auth/presentation/dto/auth.response.dto.ts index 311ad778..47784347 100644 --- a/apps/server/src/contexts/auth/presentation/dto/auth.response.dto.ts +++ b/apps/server/src/contexts/auth/presentation/dto/auth.response.dto.ts @@ -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 { diff --git a/apps/server/src/contexts/auth/presentation/middleware/tab-context.middleware.ts b/apps/server/src/contexts/auth/presentation/middleware/tab-context.middleware.ts index 1e25ca05..def4ae17 100644 --- a/apps/server/src/contexts/auth/presentation/middleware/tab-context.middleware.ts +++ b/apps/server/src/contexts/auth/presentation/middleware/tab-context.middleware.ts @@ -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({ diff --git a/apps/server/src/routes/auth.routes.ts b/apps/server/src/routes/auth.routes.ts index 9c06e26b..f6a9b62c 100644 --- a/apps/server/src/routes/auth.routes.ts +++ b/apps/server/src/routes/auth.routes.ts @@ -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";