From 829c839f9bbb31027a13c5c8830648e997950551 Mon Sep 17 00:00:00 2001 From: david Date: Fri, 21 Feb 2025 11:06:27 +0100 Subject: [PATCH] . --- .../domain/value-objects/email-address.ts | 7 +- .../src/common/domain/value-objects/name.ts | 3 +- .../src/common/domain/value-objects/slug.ts | 5 +- .../list-users/list-users.use-case.ts | 2 +- .../domain/aggregates/authenticated-user.ts | 21 +++-- .../contexts/auth/domain/aggregates/role.ts | 3 +- .../contexts/auth/domain/aggregates/user.ts | 17 ++-- .../auth/domain/entities/jwt-payload.ts | 12 +-- .../auth/domain/entities/login-data.ts | 9 +- .../auth/domain/entities/logout-data.ts | 8 +- .../auth/domain/entities/register-data.ts | 8 +- .../auth/domain/entities/tab-context.ts | 13 +-- ...authenticated-user-repository.interface.ts | 6 +- .../tab-context-repository.interface.ts | 3 +- .../repositories/user-repository.interface.ts | 6 +- .../domain/services/auth-service.interface.ts | 4 +- .../auth/domain/services/auth.service.ts | 28 ++----- .../services/tab-context-service.interface.ts | 3 +- .../domain/services/tab-context.service.ts | 3 +- .../domain/services/user-service.interface.ts | 3 +- .../auth/domain/services/user.service.ts | 5 +- .../domain/value-objects/auth-user-roles.ts | 17 +++- .../domain/value-objects/hash-password.ts | 3 +- .../domain/value-objects/plain-password.ts | 3 +- .../auth/domain/value-objects/token.ts | 3 +- .../auth/domain/value-objects/username.ts | 3 +- .../mappers/authenticated-user.mapper.ts | 57 +++++++------ .../mappers/tab-context.mapper.ts | 43 ++++++---- .../infraestructure/mappers/user.mapper.ts | 83 ++++++------------- .../passport/passport-auth-provider.ts | 5 +- .../authenticated-user.repository.ts | 16 ++-- .../sequelize/tab-context.repository.ts | 11 +-- .../sequelize/user.repository.ts | 11 +-- .../listUsers/list-users.presenter.ts | 7 +- .../controllers/login/login.presenter.ts | 13 ++- apps/server/src/routes/user.routes.ts | 4 +- 36 files changed, 211 insertions(+), 237 deletions(-) diff --git a/apps/server/src/common/domain/value-objects/email-address.ts b/apps/server/src/common/domain/value-objects/email-address.ts index 7015d4ec..5d898619 100644 --- a/apps/server/src/common/domain/value-objects/email-address.ts +++ b/apps/server/src/common/domain/value-objects/email-address.ts @@ -1,5 +1,6 @@ -import { Maybe, Result, ValueObject } from "@common/domain"; +import { Maybe, Result } from "@common/helpers"; import { z } from "zod"; +import { ValueObject } from "./value-object"; interface EmailAddressProps { value: string; @@ -47,4 +48,8 @@ export class EmailAddress extends ValueObject { getValue(): string { return this.props.value; } + + toString(): string { + return this.getValue(); + } } diff --git a/apps/server/src/common/domain/value-objects/name.ts b/apps/server/src/common/domain/value-objects/name.ts index 3b03412f..1e78c8e3 100644 --- a/apps/server/src/common/domain/value-objects/name.ts +++ b/apps/server/src/common/domain/value-objects/name.ts @@ -1,5 +1,6 @@ -import { Maybe, Result, ValueObject } from "@common/domain"; +import { Maybe, Result } from "@common/helpers"; import { z } from "zod"; +import { ValueObject } from "./value-object"; interface NameProps { value: string; diff --git a/apps/server/src/common/domain/value-objects/slug.ts b/apps/server/src/common/domain/value-objects/slug.ts index 2faa08b2..844bea57 100644 --- a/apps/server/src/common/domain/value-objects/slug.ts +++ b/apps/server/src/common/domain/value-objects/slug.ts @@ -1,5 +1,6 @@ -import { Maybe, Result, ValueObject } from "@common/domain"; +import { Maybe, Result } from "@common/helpers"; import { z } from "zod"; +import { ValueObject } from "./value-object"; interface SlugProps { value: string; @@ -35,7 +36,7 @@ export class Slug extends ValueObject { return Result.ok(Maybe.None()); } - return Slug.create(value!).map((value) => Maybe.Some(value)); + return Slug.create(value!).map((value: Slug) => Maybe.Some(value)); } getValue(): string { diff --git a/apps/server/src/contexts/auth/application/list-users/list-users.use-case.ts b/apps/server/src/contexts/auth/application/list-users/list-users.use-case.ts index dc53408a..99e283c4 100644 --- a/apps/server/src/contexts/auth/application/list-users/list-users.use-case.ts +++ b/apps/server/src/contexts/auth/application/list-users/list-users.use-case.ts @@ -1,4 +1,4 @@ -import { Result } from "@common/domain"; +import { Result } from "@common/helpers"; import { ITransactionManager } from "@common/infrastructure/database"; import { User } from "@contexts/auth/domain"; import { IUserService } from "@contexts/auth/domain/services"; diff --git a/apps/server/src/contexts/auth/domain/aggregates/authenticated-user.ts b/apps/server/src/contexts/auth/domain/aggregates/authenticated-user.ts index 06eb515f..4cb26f01 100644 --- a/apps/server/src/contexts/auth/domain/aggregates/authenticated-user.ts +++ b/apps/server/src/contexts/auth/domain/aggregates/authenticated-user.ts @@ -1,6 +1,8 @@ -import { AggregateRoot, Result, UniqueID } from "@common/domain"; +import { Result } from "@common/helpers"; + +import { AggregateRoot, EmailAddress, UniqueID } from "@common/domain"; import { UserAuthenticatedEvent } from "../events"; -import { EmailAddress, HashPassword, PlainPassword, Username } from "../value-objects"; +import { HashPassword, PlainPassword, Username } from "../value-objects"; export interface IAuthenticatedUserProps { username: Username; @@ -12,6 +14,7 @@ export interface IAuthenticatedUserProps { export interface IAuthenticatedUser { username: Username; email: EmailAddress; + hashPassword: HashPassword; accessToken: string; refreshToken: string; @@ -67,6 +70,10 @@ export class AuthenticatedUser return this.props.email; } + get hashPassword(): HashPassword { + return this.props.hashPassword; + } + get isUser(): boolean { return this.hasRole("user"); } @@ -79,14 +86,6 @@ export class AuthenticatedUser * 🔹 Devuelve una representación lista para persistencia */ toPersistenceData(): any { - return { - id: this.id.toString(), - username: this.props.username.toString(), - email: this.props.email.toString(), - hash_password: this.props.hashPassword.toString(), - roles: this.props.roles.map((role) => role.toString()), - access_token: this.accessToken, - refresh_token: this.refreshToken, - }; + return; } } diff --git a/apps/server/src/contexts/auth/domain/aggregates/role.ts b/apps/server/src/contexts/auth/domain/aggregates/role.ts index 7a5887dc..3df33c8b 100644 --- a/apps/server/src/contexts/auth/domain/aggregates/role.ts +++ b/apps/server/src/contexts/auth/domain/aggregates/role.ts @@ -1,4 +1,5 @@ -import { AggregateRoot, Result, UniqueID } from "@common/domain"; +import { AggregateRoot, UniqueID } from "@common/domain"; +import { Result } from "@common/helpers"; export interface IRoleProps {} diff --git a/apps/server/src/contexts/auth/domain/aggregates/user.ts b/apps/server/src/contexts/auth/domain/aggregates/user.ts index c8541c51..afafe3e6 100644 --- a/apps/server/src/contexts/auth/domain/aggregates/user.ts +++ b/apps/server/src/contexts/auth/domain/aggregates/user.ts @@ -1,4 +1,5 @@ -import { AggregateRoot, EmailAddress, Result, UniqueID } from "@common/domain"; +import { AggregateRoot, EmailAddress, UniqueID } from "@common/domain"; +import { Result } from "@common/helpers"; import { UserAuthenticatedEvent } from "../events"; import { Username } from "../value-objects"; @@ -14,11 +15,11 @@ export interface IUser { isUser: boolean; isAdmin: boolean; + isActive: boolean; hasRole(role: string): boolean; hasRoles(roles: string[]): boolean; getRoles(): string[]; - toPersistenceData(): any; } export class User extends AggregateRoot implements IUser { @@ -60,15 +61,7 @@ export class User extends AggregateRoot implements IUser { return this.hasRole("admin"); } - /** - * 🔹 Devuelve una representación lista para persistencia - */ - toPersistenceData(): any { - return { - id: this.id.toString(), - username: this.props.username.toString(), - email: this.props.email.toString(), - roles: this.props.roles.map((role) => role.toString()), - }; + get isActive(): boolean { + return true; } } diff --git a/apps/server/src/contexts/auth/domain/entities/jwt-payload.ts b/apps/server/src/contexts/auth/domain/entities/jwt-payload.ts index 9577fa4a..7250ddae 100644 --- a/apps/server/src/contexts/auth/domain/entities/jwt-payload.ts +++ b/apps/server/src/contexts/auth/domain/entities/jwt-payload.ts @@ -1,5 +1,5 @@ -import { DomainEntity, Result, UniqueID } from "@common/domain"; -import { EmailAddress } from "../value-objects"; +import { DomainEntity, EmailAddress, UniqueID } from "@common/domain"; +import { Result } from "@common/helpers"; export interface IJWTPayloadProps { tabId: UniqueID; @@ -23,10 +23,6 @@ export interface IJWTPayload { export class JWTPayload extends DomainEntity implements IJWTPayload { static create(props: IJWTPayloadProps): Result { - if (props.email.isEmpty()) { - return Result.fail(new Error("Email is required")); - } - return Result.ok(new JWTPayload(props)); } @@ -42,10 +38,6 @@ export class JWTPayload extends DomainEntity implements IJWTPa return Result.fail(result.error); } - if (emailOrError.data.isEmpty()) { - return Result.fail(new Error("Email is required")); - } - return JWTPayload.create({ email: emailOrError.data, userId: userIdOrError.data, diff --git a/apps/server/src/contexts/auth/domain/entities/login-data.ts b/apps/server/src/contexts/auth/domain/entities/login-data.ts index 4a839099..a39031ad 100644 --- a/apps/server/src/contexts/auth/domain/entities/login-data.ts +++ b/apps/server/src/contexts/auth/domain/entities/login-data.ts @@ -1,5 +1,6 @@ -import { DomainEntity, Result, UniqueID } from "@common/domain"; -import { EmailAddress, PlainPassword } from "../value-objects"; +import { DomainEntity, EmailAddress, UniqueID } from "@common/domain"; +import { Result } from "@common/helpers"; +import { PlainPassword } from "../value-objects"; export interface ILoginDataProps { email: EmailAddress; @@ -36,10 +37,6 @@ export class LoginData extends DomainEntity implements ILoginDa return Result.fail(result.error); } - if (emailOrError.data.isEmpty()) { - return Result.fail(new Error("Email is required")); - } - return LoginData.create({ email: emailOrError.data, plainPassword: plainPasswordOrError.data, diff --git a/apps/server/src/contexts/auth/domain/entities/logout-data.ts b/apps/server/src/contexts/auth/domain/entities/logout-data.ts index 0c1d48b6..dab5e2db 100644 --- a/apps/server/src/contexts/auth/domain/entities/logout-data.ts +++ b/apps/server/src/contexts/auth/domain/entities/logout-data.ts @@ -1,5 +1,5 @@ -import { DomainEntity, Result, UniqueID } from "@common/domain"; -import { EmailAddress } from "../value-objects"; +import { DomainEntity, EmailAddress, UniqueID } from "@common/domain"; +import { Result } from "@common/helpers"; export interface ILogoutDataProps { email: EmailAddress; @@ -32,10 +32,6 @@ export class LogoutData extends DomainEntity implements ILogou return Result.fail(result.error); } - if (emailOrError.data.isEmpty()) { - return Result.fail(new Error("Email is required")); - } - return LogoutData.create({ email: emailOrError.data, tabId: tabIdOrError.data, diff --git a/apps/server/src/contexts/auth/domain/entities/register-data.ts b/apps/server/src/contexts/auth/domain/entities/register-data.ts index 9d6b39fe..72ca5bc7 100644 --- a/apps/server/src/contexts/auth/domain/entities/register-data.ts +++ b/apps/server/src/contexts/auth/domain/entities/register-data.ts @@ -1,5 +1,6 @@ -import { DomainEntity, Result } from "@common/domain"; -import { EmailAddress, HashPassword, Username } from "../value-objects"; +import { DomainEntity, EmailAddress } from "@common/domain"; +import { Result } from "@common/helpers"; +import { HashPassword, Username } from "../value-objects"; export interface IRegisterDataProps { username: Username; @@ -37,9 +38,6 @@ export class RegisterData extends DomainEntity implements IR return Result.fail(result.error); } - if (emailOrError.data.isEmpty()) { - return Result.fail(new Error("Email is required")); - } return RegisterData.create({ username: userNameOrError.data, email: emailOrError.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 8092361a..670fc5cd 100644 --- a/apps/server/src/contexts/auth/domain/entities/tab-context.ts +++ b/apps/server/src/contexts/auth/domain/entities/tab-context.ts @@ -1,4 +1,5 @@ -import { DomainEntity, Result, UniqueID } from "@common/domain"; +import { DomainEntity, UniqueID } from "@common/domain"; +import { Result } from "@common/helpers"; export interface ITabContextProps { tabId: UniqueID; @@ -14,8 +15,6 @@ export interface ITabContextPrimitives { export interface ITabContext { tabId: UniqueID; userId: UniqueID; - - toPersistenceData(): any; } export class TabContext extends DomainEntity implements ITabContext { @@ -47,12 +46,4 @@ export class TabContext extends DomainEntity implements ITabCo get userId(): UniqueID { return this.props.userId; } - - toPersistenceData(): ITabContextPrimitives { - return { - id: this.id.toString(), - tab_id: this.tabId.toString(), - user_id: this.userId.toString(), - }; - } } diff --git a/apps/server/src/contexts/auth/domain/repositories/authenticated-user-repository.interface.ts b/apps/server/src/contexts/auth/domain/repositories/authenticated-user-repository.interface.ts index 7f591861..07833070 100644 --- a/apps/server/src/contexts/auth/domain/repositories/authenticated-user-repository.interface.ts +++ b/apps/server/src/contexts/auth/domain/repositories/authenticated-user-repository.interface.ts @@ -1,6 +1,8 @@ -import { Result } from "@common/domain"; +import { Result } from "@common/helpers"; + +import { EmailAddress } from "@common/domain"; import { AuthenticatedUser } from "../aggregates"; -import { EmailAddress, Username } from "../value-objects"; +import { Username } from "../value-objects"; export interface IAuthenticatedUserRepository { getUserByEmail(email: EmailAddress, transaction?: any): Promise>; 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 42317187..e0246403 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 @@ -1,4 +1,5 @@ -import { Result, UniqueID } from "@common/domain"; +import { UniqueID } from "@common/domain"; +import { Result } from "@common/helpers"; import { Transaction } from "sequelize"; import { TabContext } from "../entities"; diff --git a/apps/server/src/contexts/auth/domain/repositories/user-repository.interface.ts b/apps/server/src/contexts/auth/domain/repositories/user-repository.interface.ts index 47b31743..5817718a 100644 --- a/apps/server/src/contexts/auth/domain/repositories/user-repository.interface.ts +++ b/apps/server/src/contexts/auth/domain/repositories/user-repository.interface.ts @@ -1,9 +1,9 @@ -import { Result, UniqueID } from "@common/domain"; +import { EmailAddress, UniqueID } from "@common/domain"; +import { Collection, Result } from "@common/helpers"; import { User } from "../aggregates"; -import { EmailAddress } from "../value-objects"; export interface IUserRepository { - findAll(transaction?: any): Promise>; + findAll(transaction?: any): Promise, Error>>; findById(id: UniqueID, transaction?: any): Promise>; findByEmail(email: EmailAddress, transaction?: any): Promise>; } diff --git a/apps/server/src/contexts/auth/domain/services/auth-service.interface.ts b/apps/server/src/contexts/auth/domain/services/auth-service.interface.ts index b4431aa5..ab1af38e 100644 --- a/apps/server/src/contexts/auth/domain/services/auth-service.interface.ts +++ b/apps/server/src/contexts/auth/domain/services/auth-service.interface.ts @@ -1,7 +1,7 @@ -import { Result } from "@common/domain"; +import { EmailAddress } from "@common/domain"; +import { Result } from "@common/helpers"; import { AuthenticatedUser, - EmailAddress, IJWTPayload, LoginData, LogoutData, diff --git a/apps/server/src/contexts/auth/domain/services/auth.service.ts b/apps/server/src/contexts/auth/domain/services/auth.service.ts index 17203949..5e99706a 100644 --- a/apps/server/src/contexts/auth/domain/services/auth.service.ts +++ b/apps/server/src/contexts/auth/domain/services/auth.service.ts @@ -1,15 +1,9 @@ -import { Result, UniqueID } from "@common/domain"; -import { - AuthenticatedUser, - EmailAddress, - IAuthenticatedUserRepository, - IJWTPayload, - JWTPayload, - LoginData, - RegisterData, - TabContext, - Token, -} from ".."; +import { EmailAddress } from "@common/domain"; +import { Result } from "@common/helpers"; +import { AuthenticatedUser, IJWTPayload, LoginData, RegisterData, TabContext, Token } from ".."; + +import { UniqueID } from "@common/domain"; +import { IAuthenticatedUserRepository, JWTPayload } from ".."; import { JwtHelper } from "../../infraestructure/passport/jwt.helper"; import { ITabContextRepository } from "../repositories/tab-context-repository.interface"; import { IAuthService } from "./auth-service.interface"; @@ -101,11 +95,6 @@ export class AuthService implements IAuthService { let result: any; const { email, plainPassword, tabId } = loginData; - // 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 result = await this.authUserRepo.getUserByEmail(email, transaction); if (result.isFailure) { @@ -171,11 +160,6 @@ export class AuthService implements IAuthService { ): Promise> { const { email, 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.authUserRepo.getUserByEmail(email, transaction); if (userResult.isFailure) { diff --git a/apps/server/src/contexts/auth/domain/services/tab-context-service.interface.ts b/apps/server/src/contexts/auth/domain/services/tab-context-service.interface.ts index e8a8cc73..b3bc93cc 100644 --- a/apps/server/src/contexts/auth/domain/services/tab-context-service.interface.ts +++ b/apps/server/src/contexts/auth/domain/services/tab-context-service.interface.ts @@ -1,4 +1,5 @@ -import { Result, UniqueID } from "@common/domain"; +import { UniqueID } from "@common/domain"; +import { Result } from "@common/helpers"; import { TabContext } from "../entities"; export interface ITabContextService { diff --git a/apps/server/src/contexts/auth/domain/services/tab-context.service.ts b/apps/server/src/contexts/auth/domain/services/tab-context.service.ts index 56185580..e3a6460c 100644 --- a/apps/server/src/contexts/auth/domain/services/tab-context.service.ts +++ b/apps/server/src/contexts/auth/domain/services/tab-context.service.ts @@ -1,4 +1,5 @@ -import { Result, UniqueID } from "@common/domain"; +import { UniqueID } from "@common/domain"; +import { Result } from "@common/helpers"; import { TabContext } from "../entities"; import { ITabContextRepository } from "../repositories"; import { ITabContextService } from "./tab-context-service.interface"; diff --git a/apps/server/src/contexts/auth/domain/services/user-service.interface.ts b/apps/server/src/contexts/auth/domain/services/user-service.interface.ts index 84a93464..66c8a61a 100644 --- a/apps/server/src/contexts/auth/domain/services/user-service.interface.ts +++ b/apps/server/src/contexts/auth/domain/services/user-service.interface.ts @@ -1,4 +1,5 @@ -import { Result, UniqueID } from "@common/domain"; +import { UniqueID } from "@common/domain"; +import { Result } from "@common/helpers"; import { User } from "../aggregates"; export interface IUserService { diff --git a/apps/server/src/contexts/auth/domain/services/user.service.ts b/apps/server/src/contexts/auth/domain/services/user.service.ts index ab346572..f3827f6f 100644 --- a/apps/server/src/contexts/auth/domain/services/user.service.ts +++ b/apps/server/src/contexts/auth/domain/services/user.service.ts @@ -1,4 +1,5 @@ -import { Result, UniqueID } from "@common/domain"; +import { UniqueID } from "@common/domain"; +import { Result } from "@common/helpers"; import { IUserRepository, User } from ".."; import { IUserService } from "./user-service.interface"; @@ -12,7 +13,7 @@ export class UserService implements IUserService { } // Solo devolver usuarios activos - const activeUsers = usersOrError.data.filter((user) => user /*.isActive*/); + const activeUsers = usersOrError.data.filter((user) => user.isActive); return Result.ok(activeUsers); } diff --git a/apps/server/src/contexts/auth/domain/value-objects/auth-user-roles.ts b/apps/server/src/contexts/auth/domain/value-objects/auth-user-roles.ts index 3598dc17..d43dfdf1 100644 --- a/apps/server/src/contexts/auth/domain/value-objects/auth-user-roles.ts +++ b/apps/server/src/contexts/auth/domain/value-objects/auth-user-roles.ts @@ -1,14 +1,19 @@ -import { Result, ValueObject } from "@common/domain"; +import { ValueObject } from "@common/domain"; +import { Result } from "@common/helpers"; import { z } from "zod"; const RoleSchema = z.enum(["Admin", "User", "Manager", "Editor"]); -export class UserRoles extends ValueObject { +interface UserRolesProps { + value: string[]; +} + +export class UserRoles extends ValueObject { static create(roles: string[]): Result { const result = UserRoles.validate(roles); return result.success - ? Result.ok(new UserRoles(result.data)) + ? Result.ok(new UserRoles({ value: result.data })) : Result.fail(new Error("Invalid user roles")); } @@ -17,6 +22,10 @@ export class UserRoles extends ValueObject { } hasRole(role: string): boolean { - return this.props.includes(role); + return this.props.value.includes(role); + } + + getValue() { + return this.props.value; } } diff --git a/apps/server/src/contexts/auth/domain/value-objects/hash-password.ts b/apps/server/src/contexts/auth/domain/value-objects/hash-password.ts index 68ea34c1..d61ff44d 100644 --- a/apps/server/src/contexts/auth/domain/value-objects/hash-password.ts +++ b/apps/server/src/contexts/auth/domain/value-objects/hash-password.ts @@ -1,4 +1,5 @@ -import { Result, ValueObject } from "@common/domain"; +import { ValueObject } from "@common/domain"; +import { Result } from "@common/helpers"; import bcrypt from "bcrypt"; import { z } from "zod"; diff --git a/apps/server/src/contexts/auth/domain/value-objects/plain-password.ts b/apps/server/src/contexts/auth/domain/value-objects/plain-password.ts index 3a131e46..926ed623 100644 --- a/apps/server/src/contexts/auth/domain/value-objects/plain-password.ts +++ b/apps/server/src/contexts/auth/domain/value-objects/plain-password.ts @@ -1,4 +1,5 @@ -import { Result, ValueObject } from "@common/domain"; +import { ValueObject } from "@common/domain"; +import { Result } from "@common/helpers"; import { z } from "zod"; interface PlainPasswordProps { diff --git a/apps/server/src/contexts/auth/domain/value-objects/token.ts b/apps/server/src/contexts/auth/domain/value-objects/token.ts index 1440eebf..2cc72f22 100644 --- a/apps/server/src/contexts/auth/domain/value-objects/token.ts +++ b/apps/server/src/contexts/auth/domain/value-objects/token.ts @@ -1,4 +1,5 @@ -import { Result, ValueObject } from "@common/domain"; +import { ValueObject } from "@common/domain"; +import { Result } from "@common/helpers"; import { z } from "zod"; interface TokenProps { diff --git a/apps/server/src/contexts/auth/domain/value-objects/username.ts b/apps/server/src/contexts/auth/domain/value-objects/username.ts index 96d96c90..fa37aaae 100644 --- a/apps/server/src/contexts/auth/domain/value-objects/username.ts +++ b/apps/server/src/contexts/auth/domain/value-objects/username.ts @@ -1,4 +1,5 @@ -import { Result, ValueObject } from "@common/domain"; +import { ValueObject } from "@common/domain"; +import { Result } from "@common/helpers"; import { z } from "zod"; interface UsernameProps { diff --git a/apps/server/src/contexts/auth/infraestructure/mappers/authenticated-user.mapper.ts b/apps/server/src/contexts/auth/infraestructure/mappers/authenticated-user.mapper.ts index 94b4c736..e128bce4 100644 --- a/apps/server/src/contexts/auth/infraestructure/mappers/authenticated-user.mapper.ts +++ b/apps/server/src/contexts/auth/infraestructure/mappers/authenticated-user.mapper.ts @@ -1,26 +1,25 @@ -import { EmailAddress, Result, UniqueID } from "@common/domain"; +import { EmailAddress, UniqueID } from "@common/domain"; +import { Result } from "@common/helpers"; +import { ISequelizeMapper, MapperParamsType, SequelizeMapper } from "@common/infrastructure"; import { AuthenticatedUser, HashPassword, Username } from "@contexts/auth/domain"; -import { AuthUserModel } from "../sequelize"; +import { AuthUserCreationAttributes, AuthUserModel } from "../sequelize"; -export interface IAuthenticatedUserMapper { - toDomain(entity: AuthUserModel): Result; - toPersistence(aggregate: AuthenticatedUser): AuthUserModel; -} - -class AuthenticatedUserMapper implements IAuthenticatedUserMapper { - /** - * 🔹 Convierte una entidad de la base de datos en un agregado de dominio `AuthenticatedUser` - */ - toDomain(entity: AuthUserModel): Result { - if (!entity) { - return Result.fail(new Error("Entity not found")); - } +export interface IAuthenticatedUserMapper + extends ISequelizeMapper {} +export class AuthenticatedUserMapper + extends SequelizeMapper + implements IAuthenticatedUserMapper +{ + public mapToDomain( + source: AuthUserModel, + params?: MapperParamsType + ): Result { // Crear Value Objects asegurando que sean válidos - const uniqueIdResult = UniqueID.create(entity.id); - const usernameResult = Username.create(entity.username); - const passwordHashResult = HashPassword.createFromHash(entity.hash_password); - const emailResult = EmailAddress.create(entity.email); + const uniqueIdResult = UniqueID.create(source.id); + const usernameResult = Username.create(source.username); + const passwordHashResult = HashPassword.createFromHash(source.hash_password); + const emailResult = EmailAddress.create(source.email); // Validar que no haya errores en la creación de los Value Objects const okOrError = Result.combine([ @@ -39,17 +38,25 @@ class AuthenticatedUserMapper implements IAuthenticatedUserMapper { username: usernameResult.data!, email: emailResult.data!, hashPassword: passwordHashResult.data!, - roles: entity.roles || [], + roles: source.roles || [], }, uniqueIdResult.data! ); } - /** - * 🔹 Convierte un agregado `AuthenticatedUser` en un objeto listo para persistencia - */ - toPersistence(authenticatedUser: AuthenticatedUser): AuthUserModel { - return authenticatedUser.toPersistenceData(); + public mapToPersistence( + source: AuthenticatedUser, + params?: MapperParamsType + ): Result { + return Result.ok({ + id: source.id.toString(), + username: source.username.toString(), + email: source.email.toString(), + hash_password: source.hashPassword.toString(), + roles: source.getRoles().map((role) => role.toString()), + //access_token: source.accessToken, + //refresh_token: source.refreshToken, + }); } } 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 d1aecc7e..74b08d6f 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,22 +1,24 @@ -import { Result, UniqueID } from "@common/domain"; +import { UniqueID } from "@common/domain"; +import { Result } from "@common/helpers"; +import { ISequelizeMapper, MapperParamsType, SequelizeMapper } from "@common/infrastructure"; import { TabContext } from "@contexts/auth/domain"; -import { TabContextModel } from "../sequelize"; +import { TabContextCreationAttributes, TabContextModel } from "../sequelize"; -export interface ITabContextMapper { - toDomain(entity: TabContextModel): Result; - toPersistence(aggregate: TabContext): TabContextModel; -} - -class TabContextMapper implements ITabContextMapper { - toDomain(entity: TabContextModel): Result { - if (!entity) { - return Result.fail(new Error("Entity not found")); - } +export interface ITabContextMapper + extends ISequelizeMapper {} +export class TabContextMapper + extends SequelizeMapper + implements ITabContextMapper +{ + public mapToDomain( + source: TabContextModel, + params?: MapperParamsType + ): Result { // Crear Value Objects asegurando que sean válidos - const uniqueIdResult = UniqueID.create(entity.id); - const tabIdResult = UniqueID.create(entity.tab_id); - const userIdResult = UniqueID.create(entity.user_id); + const uniqueIdResult = UniqueID.create(source.id); + const tabIdResult = UniqueID.create(source.tab_id); + const userIdResult = UniqueID.create(source.user_id); //const companyIdResult = UniqueID.create(entity.company_id, false); //const brachIdResult = UniqueID.create(entity.branch_id, false); @@ -44,8 +46,15 @@ class TabContextMapper implements ITabContextMapper { ); } - toPersistence(tabContext: TabContext): TabContextModel { - return tabContext.toPersistenceData(); + public mapToPersistence( + source: TabContext, + params?: MapperParamsType + ): Result { + return Result.ok({ + id: source.id.toString(), + tab_id: source.tabId.toString(), + user_id: source.userId.toString(), + }); } } diff --git a/apps/server/src/contexts/auth/infraestructure/mappers/user.mapper.ts b/apps/server/src/contexts/auth/infraestructure/mappers/user.mapper.ts index 582ebf87..458ff5b2 100644 --- a/apps/server/src/contexts/auth/infraestructure/mappers/user.mapper.ts +++ b/apps/server/src/contexts/auth/infraestructure/mappers/user.mapper.ts @@ -1,28 +1,24 @@ -import { EmailAddress, Result, UniqueID } from "@common/domain"; +import { EmailAddress, UniqueID } from "@common/domain"; +import { Result } from "@common/helpers"; +import { + ISequelizeMapper, + MapperParamsType, + SequelizeMapper, +} from "@common/infrastructure/sequelize/sequelize-mapper"; import { User, Username } from "@contexts/auth/domain"; -import { UserModel } from "../sequelize"; +import { UserCreationAttributes, UserModel } from "../sequelize"; -export interface IUserMapper { - toDomain(entity: UserModel): Result; - toDomainArray(entities: UserModel[]): Result; - - toPersistence(aggregate: User): UserModel; - toPersistenceArray(users: User[]): UserModel[]; -} - -class UserMapper implements IUserMapper { - /** - * 🔹 Convierte una entidad de la base de datos en un agregado de dominio `User` - */ - toDomain(entity: UserModel): Result { - if (!entity) { - return Result.fail(new Error("Entity not found")); - } +export interface IUserMapper extends ISequelizeMapper {} +class UserMapper + extends SequelizeMapper + implements IUserMapper +{ + public mapToDomain(source: UserModel, params?: MapperParamsType): Result { // Crear Value Objects asegurando que sean válidos - const uniqueIdResult = UniqueID.create(entity.id); - const usernameResult = Username.create(entity.username); - const emailResult = EmailAddress.create(entity.email); + const uniqueIdResult = UniqueID.create(source.id); + const usernameResult = Username.create(source.username); + const emailResult = EmailAddress.create(source.email); // Validar que no haya errores en la creación de los Value Objects const okOrError = Result.combine([uniqueIdResult, usernameResult, emailResult]); @@ -42,41 +38,16 @@ class UserMapper implements IUserMapper { ); } - /** - * 🔹 Convierte un array de entidades de la base de datos en un array de agregados de dominio `User` - */ - toDomainArray(entities: UserModel[]): Result { - if (!Array.isArray(entities) || entities.length === 0) { - return Result.fail(new Error("Entities array is empty or invalid")); - } - - const usersResults = entities.map(this.toDomain); - - const okOrError = Result.combine(usersResults); - if (okOrError.isFailure) { - return Result.fail(okOrError.error); - } - - const result = usersResults.map((result) => result.data!); - return Result.ok(result); - } - - /** - * 🔹 Convierte un agregado `User` en un objeto listo para persistencia - */ - toPersistence(user: User): UserModel { - return user.toPersistenceData(); - } - - /** - * 🔹 Convierte un array de agregados `User` en un array de objetos listos para persistencia - */ - toPersistenceArray(users: User[]): UserModel[] { - if (!Array.isArray(users) || users.length === 0) { - return []; - } - - return users.map(this.toPersistence); + public mapToPersistence( + source: User, + params?: MapperParamsType + ): Result { + return Result.ok({ + id: source.id.toString(), + username: source.username.toString(), + email: source.email.toString(), + //roles: source.getRoles().map((role) => role.toString()), + }); } } diff --git a/apps/server/src/contexts/auth/infraestructure/passport/passport-auth-provider.ts b/apps/server/src/contexts/auth/infraestructure/passport/passport-auth-provider.ts index 68cc3760..cbf22361 100644 --- a/apps/server/src/contexts/auth/infraestructure/passport/passport-auth-provider.ts +++ b/apps/server/src/contexts/auth/infraestructure/passport/passport-auth-provider.ts @@ -1,9 +1,10 @@ import { NextFunction, Response } from "express"; -import { Result, UniqueID } from "@common/domain"; +import { EmailAddress, UniqueID } from "@common/domain"; +import { Result } from "@common/helpers"; import { ITransactionManager } from "@common/infrastructure/database"; import { logger } from "@common/infrastructure/logger"; -import { EmailAddress, TabContext } from "@contexts/auth/domain"; +import { TabContext } from "@contexts/auth/domain"; import { IAuthService, ITabContextService } from "@contexts/auth/domain/services"; import passport from "passport"; import { ExtractJwt, Strategy as JwtStrategy } from "passport-jwt"; diff --git a/apps/server/src/contexts/auth/infraestructure/sequelize/authenticated-user.repository.ts b/apps/server/src/contexts/auth/infraestructure/sequelize/authenticated-user.repository.ts index fcbc508c..f1782ee0 100644 --- a/apps/server/src/contexts/auth/infraestructure/sequelize/authenticated-user.repository.ts +++ b/apps/server/src/contexts/auth/infraestructure/sequelize/authenticated-user.repository.ts @@ -1,11 +1,7 @@ -import { Result } from "@common/domain"; +import { EmailAddress } from "@common/domain"; +import { Result } from "@common/helpers"; import { SequelizeRepository } from "@common/infrastructure"; -import { - AuthenticatedUser, - EmailAddress, - IAuthenticatedUserRepository, - Username, -} from "@contexts/auth/domain"; +import { AuthenticatedUser, IAuthenticatedUserRepository, Username } from "@contexts/auth/domain"; import { Transaction } from "sequelize"; import { authenticatedUserMapper, IAuthenticatedUserMapper } from "../mappers"; import { AuthUserModel } from "./auth-user.model"; @@ -75,7 +71,7 @@ class AuthenticatedUserRepository return Result.fail(new Error("User with email not exists")); } - return this._mapper.toDomain(rawUser); + return this._mapper.mapToDomain(rawUser); } catch (error: any) { return this._handleDatabaseError(error, this._customErrorMapper); } @@ -86,8 +82,8 @@ class AuthenticatedUserRepository transaction?: Transaction ): Promise> { try { - const persistenceData = this._mapper.toPersistence(user); - await AuthUserModel.create(persistenceData, { transaction }); + const persistenceData = this._mapper.mapToPersistence(user); + await AuthUserModel.create(persistenceData.data, { transaction }); return Result.ok(); } catch (error: any) { return this._handleDatabaseError(error, this._customErrorMapper); 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 531f7606..45b3e228 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 @@ -1,4 +1,5 @@ -import { Result, UniqueID } from "@common/domain"; +import { UniqueID } from "@common/domain"; +import { Result } from "@common/helpers"; import { SequelizeRepository } from "@common/infrastructure"; import { ITabContextRepository, TabContext } from "@contexts/auth/domain/"; import { Op, Transaction } from "sequelize"; @@ -44,7 +45,7 @@ class TabContextRepository return Result.fail(new Error("Tab context not exists")); } - return this._mapper.toDomain(rawContext); + return this._mapper.mapToDomain(rawContext); } catch (error: any) { return this._handleDatabaseError(error, this._customErrorMapper); } @@ -78,17 +79,17 @@ class TabContextRepository ): Promise> { try { const { userId, tabId } = context; - const data = this._mapper.toPersistence(context); + const persistenceData = this._mapper.mapToPersistence(context); // Si existe el contexto de ese tabId, lo actualizo. if (await this._exists(TabContextModel, "tab_id", tabId.toString())) { - await TabContextModel.update(data, { + await TabContextModel.update(persistenceData.data, { where: { [Op.and]: [{ tab_id: tabId.toString() }, { user_id: userId.toString() }] }, transaction, }); } else { - await TabContextModel.create(data, { + await TabContextModel.create(persistenceData.data, { include: [{ all: true }], transaction, }); diff --git a/apps/server/src/contexts/auth/infraestructure/sequelize/user.repository.ts b/apps/server/src/contexts/auth/infraestructure/sequelize/user.repository.ts index 681f2877..f9a85000 100644 --- a/apps/server/src/contexts/auth/infraestructure/sequelize/user.repository.ts +++ b/apps/server/src/contexts/auth/infraestructure/sequelize/user.repository.ts @@ -1,4 +1,5 @@ -import { EmailAddress, Result, UniqueID } from "@common/domain"; +import { EmailAddress, UniqueID } from "@common/domain"; +import { Collection, Result } from "@common/helpers"; import { SequelizeRepository } from "@common/infrastructure"; import { IUserRepository, User } from "@contexts/auth/domain"; import { Transaction } from "sequelize"; @@ -24,7 +25,7 @@ class UserRepository extends SequelizeRepository implements IUserRepositor this._mapper = mapper; } - async findAll(transaction?: Transaction): Promise> { + async findAll(transaction?: Transaction): Promise, Error>> { try { const rawUsers: any = await this._findAll(UserModel, {}, transaction); @@ -32,7 +33,7 @@ class UserRepository extends SequelizeRepository implements IUserRepositor return Result.fail(new Error("User with email not exists")); } - return this._mapper.toDomainArray(rawUsers); + return this._mapper.mapArrayToDomain(rawUsers); } catch (error: any) { return this._handleDatabaseError(error, this._customErrorMapper); } @@ -46,7 +47,7 @@ class UserRepository extends SequelizeRepository implements IUserRepositor return Result.fail(new Error(`User with id ${id.toString()} not exists`)); } - return this._mapper.toDomain(rawUser); + return this._mapper.mapToDomain(rawUser); } catch (error: any) { return this._handleDatabaseError(error, this._customErrorMapper); } @@ -60,7 +61,7 @@ class UserRepository extends SequelizeRepository implements IUserRepositor return Result.fail(new Error(`User with email ${email.toString()} not exists`)); } - return this._mapper.toDomain(rawUser); + return this._mapper.mapToDomain(rawUser); } catch (error: any) { return this._handleDatabaseError(error, this._customErrorMapper); } diff --git a/apps/server/src/contexts/auth/presentation/controllers/listUsers/list-users.presenter.ts b/apps/server/src/contexts/auth/presentation/controllers/listUsers/list-users.presenter.ts index 9f714344..ee8d20cf 100644 --- a/apps/server/src/contexts/auth/presentation/controllers/listUsers/list-users.presenter.ts +++ b/apps/server/src/contexts/auth/presentation/controllers/listUsers/list-users.presenter.ts @@ -1,3 +1,4 @@ +import { ensureString } from "@common/helpers"; import { User } from "@contexts/auth/domain"; import { IListUsersResponseDTO } from "../../dto"; @@ -8,8 +9,8 @@ export interface IListUsersPresenter { export const listUsersPresenter: IListUsersPresenter = { toDTO: (users: User[]): IListUsersResponseDTO[] => users.map((user) => ({ - id: user.id.toString(), - email: user.email.toString(), - username: user.username.toString(), + id: ensureString(user.id.toString()), + email: ensureString(user.email.toString()), + username: ensureString(user.username.toString()), })), }; 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 1dc1e766..fa1e3aad 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 @@ -27,9 +27,18 @@ export const loginPresenter: ILoginPresenter = { tokens: { accessToken, refreshToken }, } = data; - const userData = user.toPersistenceData(); + const userData = { + id: user.id.toString(), + username: user.username.toString(), + email: user.email.toString(), + //roles: user.getRoles().map((role) => role.toString()), + }; - const tabContextData = tabContext.toPersistenceData(); + const tabContextData = { + id: tabContext.id.toString(), + tab_id: tabContext.tabId.toString(), + user_id: tabContext.userId.toString(), + }; return { user: { diff --git a/apps/server/src/routes/user.routes.ts b/apps/server/src/routes/user.routes.ts index 9d65978d..53b6d5fd 100644 --- a/apps/server/src/routes/user.routes.ts +++ b/apps/server/src/routes/user.routes.ts @@ -1,5 +1,5 @@ import { validateRequestDTO } from "@common/presentation"; -import { checkTabContext, checkUserIsAdmin } from "@contexts/auth/infraestructure"; +import { checkTabContext } from "@contexts/auth/infraestructure"; import { listUsersController, ListUsersSchema } from "@contexts/auth/presentation"; import { NextFunction, Request, Response, Router } from "express"; @@ -10,7 +10,7 @@ export const userRouter = (appRouter: Router) => { "/", validateRequestDTO(ListUsersSchema), checkTabContext, - checkUserIsAdmin, + //checkUserIsAdmin, (req: Request, res: Response, next: NextFunction) => { listUsersController().execute(req, res, next); }