.
This commit is contained in:
parent
1685a44fc2
commit
7cd155f331
@ -1,10 +1,11 @@
|
|||||||
{
|
{
|
||||||
"semi": true,
|
"printWidth": 130,
|
||||||
"printWidth": 80,
|
"tabWidth": 4,
|
||||||
"useTabs": false,
|
"useTabs": false,
|
||||||
"endOfLine": "auto",
|
"semi": true,
|
||||||
|
|
||||||
"trailingComma": "all",
|
|
||||||
"singleQuote": false,
|
"singleQuote": false,
|
||||||
"bracketSpacing": true
|
"trailingComma": "all",
|
||||||
|
"bracketSpacing": true,
|
||||||
|
"jsxBracketSameLine": true,
|
||||||
|
"arrowParens": "always"
|
||||||
}
|
}
|
||||||
|
|||||||
1
.vscode/settings.json
vendored
1
.vscode/settings.json
vendored
@ -1,5 +1,4 @@
|
|||||||
{
|
{
|
||||||
//"typescript.surveys.enabled": false,
|
|
||||||
"editor.codeActionsOnSave": {
|
"editor.codeActionsOnSave": {
|
||||||
"source.organizeImports": "explicit",
|
"source.organizeImports": "explicit",
|
||||||
"source.fixAll.eslint": "explicit"
|
"source.fixAll.eslint": "explicit"
|
||||||
|
|||||||
@ -4,8 +4,8 @@ module.exports = {
|
|||||||
"9d6c903873c341816995a8be0355c6f0d6d471fc6aedacf50790e9b1e49c45b3",
|
"9d6c903873c341816995a8be0355c6f0d6d471fc6aedacf50790e9b1e49c45b3",
|
||||||
refresh_secret_key:
|
refresh_secret_key:
|
||||||
"3972dc40c69327b65352ed097419213b0b75561169dba562410b85660bb1f305",
|
"3972dc40c69327b65352ed097419213b0b75561169dba562410b85660bb1f305",
|
||||||
token_expiration: "5m",
|
token_expiration: "7d",
|
||||||
refresh_token_expiration: "7d",
|
refresh_token_expiration: "30d",
|
||||||
},
|
},
|
||||||
|
|
||||||
database: {
|
database: {
|
||||||
|
|||||||
@ -3,7 +3,6 @@ import {
|
|||||||
IUseCaseError,
|
IUseCaseError,
|
||||||
IUseCaseRequest,
|
IUseCaseRequest,
|
||||||
UseCaseError,
|
UseCaseError,
|
||||||
handleUseCaseError,
|
|
||||||
} from "@/contexts/common/application";
|
} from "@/contexts/common/application";
|
||||||
import { IRepositoryManager } from "@/contexts/common/domain";
|
import { IRepositoryManager } from "@/contexts/common/domain";
|
||||||
import { IInfrastructureError } from "@/contexts/common/infrastructure";
|
import { IInfrastructureError } from "@/contexts/common/infrastructure";
|
||||||
@ -49,7 +48,7 @@ export class FindUserByEmailUseCase
|
|||||||
const emailOrError = ensureEmailIsValid(email);
|
const emailOrError = ensureEmailIsValid(email);
|
||||||
if (emailOrError.isFailure) {
|
if (emailOrError.isFailure) {
|
||||||
return Result.fail(
|
return Result.fail(
|
||||||
handleUseCaseError(
|
UseCaseError.create(
|
||||||
UseCaseError.INVALID_INPUT_DATA,
|
UseCaseError.INVALID_INPUT_DATA,
|
||||||
"Email or password is not valid",
|
"Email or password is not valid",
|
||||||
emailOrError.error,
|
emailOrError.error,
|
||||||
@ -66,7 +65,7 @@ export class FindUserByEmailUseCase
|
|||||||
|
|
||||||
if (user === null) {
|
if (user === null) {
|
||||||
return Result.fail(
|
return Result.fail(
|
||||||
handleUseCaseError(
|
UseCaseError.create(
|
||||||
UseCaseError.NOT_FOUND_ERROR,
|
UseCaseError.NOT_FOUND_ERROR,
|
||||||
`User with email ${email} not found`,
|
`User with email ${email} not found`,
|
||||||
),
|
),
|
||||||
@ -76,7 +75,7 @@ export class FindUserByEmailUseCase
|
|||||||
} catch (error: unknown) {
|
} catch (error: unknown) {
|
||||||
const _error = error as IInfrastructureError;
|
const _error = error as IInfrastructureError;
|
||||||
return Result.fail(
|
return Result.fail(
|
||||||
handleUseCaseError(
|
UseCaseError.create(
|
||||||
UseCaseError.REPOSITORY_ERROR,
|
UseCaseError.REPOSITORY_ERROR,
|
||||||
"Error al buscar el usuario",
|
"Error al buscar el usuario",
|
||||||
_error,
|
_error,
|
||||||
|
|||||||
@ -2,12 +2,11 @@ import {
|
|||||||
IUseCase,
|
IUseCase,
|
||||||
IUseCaseError,
|
IUseCaseError,
|
||||||
UseCaseError,
|
UseCaseError,
|
||||||
handleUseCaseError,
|
|
||||||
} from "@/contexts/common/application";
|
} from "@/contexts/common/application";
|
||||||
import { IRepositoryManager } from "@/contexts/common/domain";
|
import { IRepositoryManager } from "@/contexts/common/domain";
|
||||||
import { IInfrastructureError } from "@/contexts/common/infrastructure";
|
import { IInfrastructureError } from "@/contexts/common/infrastructure";
|
||||||
import { ISequelizeAdapter } from "@/contexts/common/infrastructure/sequelize";
|
import { ISequelizeAdapter } from "@/contexts/common/infrastructure/sequelize";
|
||||||
import { ILogin_DTO, Result, ensureUserEmailIsValid } from "@shared/contexts";
|
import { ILogin_DTO, Result, ensureEmailIsValid } from "@shared/contexts";
|
||||||
import { AuthUser } from "../domain";
|
import { AuthUser } from "../domain";
|
||||||
import { findUserByEmail } from "./authServices";
|
import { findUserByEmail } from "./authServices";
|
||||||
|
|
||||||
@ -38,10 +37,10 @@ export class LoginUseCase
|
|||||||
|
|
||||||
// Validaciones de datos
|
// Validaciones de datos
|
||||||
|
|
||||||
const emailOrError = ensureUserEmailIsValid(email);
|
const emailOrError = ensureEmailIsValid(email);
|
||||||
if (emailOrError.isFailure) {
|
if (emailOrError.isFailure) {
|
||||||
return Result.fail(
|
return Result.fail(
|
||||||
handleUseCaseError(
|
UseCaseError.create(
|
||||||
UseCaseError.INVALID_INPUT_DATA,
|
UseCaseError.INVALID_INPUT_DATA,
|
||||||
"Email or password is not valid",
|
"Email or password is not valid",
|
||||||
emailOrError.error,
|
emailOrError.error,
|
||||||
@ -58,7 +57,7 @@ export class LoginUseCase
|
|||||||
);
|
);
|
||||||
if (user === null || !user.verifyPassword(password)) {
|
if (user === null || !user.verifyPassword(password)) {
|
||||||
return Result.fail(
|
return Result.fail(
|
||||||
handleUseCaseError(
|
UseCaseError.create(
|
||||||
UseCaseError.INVALID_INPUT_DATA,
|
UseCaseError.INVALID_INPUT_DATA,
|
||||||
"Email or password is not valid",
|
"Email or password is not valid",
|
||||||
),
|
),
|
||||||
@ -68,7 +67,7 @@ export class LoginUseCase
|
|||||||
} catch (error: unknown) {
|
} catch (error: unknown) {
|
||||||
const _error = error as IInfrastructureError;
|
const _error = error as IInfrastructureError;
|
||||||
return Result.fail(
|
return Result.fail(
|
||||||
handleUseCaseError(
|
UseCaseError.create(
|
||||||
UseCaseError.REPOSITORY_ERROR,
|
UseCaseError.REPOSITORY_ERROR,
|
||||||
"Error al buscar el usuario",
|
"Error al buscar el usuario",
|
||||||
_error,
|
_error,
|
||||||
|
|||||||
@ -1,10 +1,7 @@
|
|||||||
import { config } from "@/config";
|
import { config } from "@/config";
|
||||||
import { AuthUser } from "@/contexts/auth/domain";
|
import { AuthUser } from "@/contexts/auth/domain";
|
||||||
import { IServerError } from "@/contexts/common/domain/errors";
|
import { IServerError } from "@/contexts/common/domain/errors";
|
||||||
import {
|
import { InfrastructureError } from "@/contexts/common/infrastructure";
|
||||||
InfrastructureError,
|
|
||||||
handleInfrastructureError,
|
|
||||||
} from "@/contexts/common/infrastructure";
|
|
||||||
import { ExpressController } from "@/contexts/common/infrastructure/express";
|
import { ExpressController } from "@/contexts/common/infrastructure/express";
|
||||||
import { ILogin_Response_DTO } from "@shared/contexts";
|
import { ILogin_Response_DTO } from "@shared/contexts";
|
||||||
import JWT from "jsonwebtoken";
|
import JWT from "jsonwebtoken";
|
||||||
@ -34,7 +31,7 @@ export class LoginController extends ExpressController {
|
|||||||
|
|
||||||
if (!user) {
|
if (!user) {
|
||||||
const errorMessage = "Unexpected missing user data";
|
const errorMessage = "Unexpected missing user data";
|
||||||
const infraError = handleInfrastructureError(
|
const infraError = InfrastructureError.create(
|
||||||
InfrastructureError.UNEXCEPTED_ERROR,
|
InfrastructureError.UNEXCEPTED_ERROR,
|
||||||
errorMessage,
|
errorMessage,
|
||||||
);
|
);
|
||||||
|
|||||||
@ -2,7 +2,7 @@ import {
|
|||||||
ISequelizeMapper,
|
ISequelizeMapper,
|
||||||
SequelizeMapper,
|
SequelizeMapper,
|
||||||
} from "@/contexts/common/infrastructure";
|
} from "@/contexts/common/infrastructure";
|
||||||
import { Email, Name, UniqueID } from "@shared/contexts";
|
import { Email, Name, Password, UniqueID } from "@shared/contexts";
|
||||||
import { AuthUser, IAuthUserProps } from "../../domain/entities";
|
import { AuthUser, IAuthUserProps } from "../../domain/entities";
|
||||||
import { IAuthContext } from "../Auth.context";
|
import { IAuthContext } from "../Auth.context";
|
||||||
import {
|
import {
|
||||||
@ -29,7 +29,11 @@ class UserMapper
|
|||||||
const props: IAuthUserProps = {
|
const props: IAuthUserProps = {
|
||||||
name: this.mapsValue(source, "name", Name.create),
|
name: this.mapsValue(source, "name", Name.create),
|
||||||
email: this.mapsValue(source, "email", Email.create),
|
email: this.mapsValue(source, "email", Email.create),
|
||||||
hashed_password: source.password,
|
hashed_password: this.mapsValue(
|
||||||
|
source,
|
||||||
|
"password",
|
||||||
|
Password.createFromHashedText,
|
||||||
|
),
|
||||||
};
|
};
|
||||||
|
|
||||||
const id = this.mapsValue(source, "id", UniqueID.create);
|
const id = this.mapsValue(source, "id", UniqueID.create);
|
||||||
|
|||||||
@ -2,7 +2,6 @@ import {
|
|||||||
IUseCase,
|
IUseCase,
|
||||||
IUseCaseError,
|
IUseCaseError,
|
||||||
UseCaseError,
|
UseCaseError,
|
||||||
handleUseCaseError,
|
|
||||||
} from "@/contexts/common/application/useCases";
|
} from "@/contexts/common/application/useCases";
|
||||||
import { IRepositoryManager } from "@/contexts/common/domain";
|
import { IRepositoryManager } from "@/contexts/common/domain";
|
||||||
import {
|
import {
|
||||||
@ -67,7 +66,7 @@ export class ListArticlesUseCase
|
|||||||
} catch (error: unknown) {
|
} catch (error: unknown) {
|
||||||
const _error = error as IInfrastructureError;
|
const _error = error as IInfrastructureError;
|
||||||
return Result.fail(
|
return Result.fail(
|
||||||
handleUseCaseError(
|
UseCaseError.create(
|
||||||
UseCaseError.REPOSITORY_ERROR,
|
UseCaseError.REPOSITORY_ERROR,
|
||||||
"Error al listar el catálogo",
|
"Error al listar el catálogo",
|
||||||
_error,
|
_error,
|
||||||
|
|||||||
@ -2,6 +2,10 @@ import { IServerError, ServerError } from "../../domain/errors";
|
|||||||
|
|
||||||
export interface IUseCaseError extends IServerError {}
|
export interface IUseCaseError extends IServerError {}
|
||||||
|
|
||||||
|
export type UseCaseErrorDetails = {
|
||||||
|
path?: string;
|
||||||
|
} & Record<string, any>;
|
||||||
|
|
||||||
export class UseCaseError extends ServerError implements IUseCaseError {
|
export class UseCaseError extends ServerError implements IUseCaseError {
|
||||||
public static readonly INVALID_REQUEST_PARAM = "INVALID_REQUEST_PARAM";
|
public static readonly INVALID_REQUEST_PARAM = "INVALID_REQUEST_PARAM";
|
||||||
public static readonly INVALID_INPUT_DATA = "INVALID_INPUT_DATA";
|
public static readonly INVALID_INPUT_DATA = "INVALID_INPUT_DATA";
|
||||||
@ -13,16 +17,8 @@ export class UseCaseError extends ServerError implements IUseCaseError {
|
|||||||
public static create(
|
public static create(
|
||||||
code: string,
|
code: string,
|
||||||
message: string,
|
message: string,
|
||||||
details?: Record<string, any>,
|
details?: UseCaseErrorDetails,
|
||||||
): UseCaseError {
|
): UseCaseError {
|
||||||
return new UseCaseError(code, message, details);
|
return new UseCaseError(code, message, details);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function handleUseCaseError(
|
|
||||||
code: string,
|
|
||||||
message: string,
|
|
||||||
payload?: Record<string, any>,
|
|
||||||
): IUseCaseError {
|
|
||||||
return UseCaseError.create(code, message, payload);
|
|
||||||
}
|
|
||||||
|
|||||||
@ -18,42 +18,28 @@ export class InfrastructureError
|
|||||||
public static create(
|
public static create(
|
||||||
code: string,
|
code: string,
|
||||||
message: string,
|
message: string,
|
||||||
payload?: Record<string, any>,
|
error?: UseCaseError | ValidationError,
|
||||||
): InfrastructureError {
|
): InfrastructureError {
|
||||||
|
let payload = {};
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
if (error.name === "ValidationError") {
|
||||||
|
//Joi error => error.details
|
||||||
|
payload = (<ValidationError>error).details;
|
||||||
|
} else {
|
||||||
|
// UseCaseError
|
||||||
|
const _error = <UseCaseError>error;
|
||||||
|
const _payload = Array.isArray(_error.payload)
|
||||||
|
? _error.payload
|
||||||
|
: [_error.payload];
|
||||||
|
|
||||||
|
payload = _payload.map((item: Record<string, any>) => ({
|
||||||
|
path: item.path,
|
||||||
|
message: error.message,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return new InfrastructureError(code, message, payload);
|
return new InfrastructureError(code, message, payload);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function _isJoiError(error: Error) {
|
|
||||||
return error.name === "ValidationError";
|
|
||||||
}
|
|
||||||
|
|
||||||
export function handleInfrastructureError(
|
|
||||||
code: string,
|
|
||||||
message: string,
|
|
||||||
error?: Error, // UseCaseError | ValidationError
|
|
||||||
): IInfrastructureError {
|
|
||||||
let payload = {};
|
|
||||||
|
|
||||||
if (error) {
|
|
||||||
if (_isJoiError(error)) {
|
|
||||||
//Joi => error.details
|
|
||||||
payload = (<ValidationError>error).details;
|
|
||||||
} else {
|
|
||||||
// UseCaseError
|
|
||||||
/*const useCaseError = <UseCaseError>error;
|
|
||||||
if (useCaseError.payload.path) {
|
|
||||||
const errorItem = {};
|
|
||||||
errorItem[`${useCaseError.payload.path}`] = useCaseError.message;
|
|
||||||
payload = {+
|
|
||||||
errors: [errorItem],
|
|
||||||
};
|
|
||||||
}*/
|
|
||||||
payload = (<UseCaseError>error).payload;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log(payload);
|
|
||||||
|
|
||||||
return InfrastructureError.create(code, message, payload);
|
|
||||||
}
|
|
||||||
|
|||||||
@ -51,7 +51,7 @@ function generateExpressError(
|
|||||||
if (item.path) {
|
if (item.path) {
|
||||||
return item.path
|
return item.path
|
||||||
? {
|
? {
|
||||||
[String(item.path)]: useCaseError.message,
|
[String(item.path)]: item.message || useCaseError.message,
|
||||||
}
|
}
|
||||||
: {};
|
: {};
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@ -33,4 +33,8 @@ function applyMiddleware(middlewares: string | Array<string>) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export { applyMiddleware, registerMiddleware };
|
function createMiddlewareMap() {
|
||||||
|
return new Map<string, Express.RequestHandler>();
|
||||||
|
}
|
||||||
|
|
||||||
|
export { applyMiddleware, createMiddlewareMap, registerMiddleware };
|
||||||
|
|||||||
@ -73,7 +73,7 @@ export class SequelizeAdapter implements ISequelizeAdapter {
|
|||||||
return this._connection.sync(params);
|
return this._connection.sync(params);
|
||||||
}
|
}
|
||||||
|
|
||||||
public getModel(modelName: string) {
|
public getModel(modelName: string): any {
|
||||||
if (this.hasModel(modelName)) {
|
if (this.hasModel(modelName)) {
|
||||||
return this._models[modelName];
|
return this._models[modelName];
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,10 +1,11 @@
|
|||||||
import { Model, Sequelize } from "sequelize";
|
import { Model, ModelStatic, Sequelize } from "sequelize";
|
||||||
|
|
||||||
interface ISequelizeModel extends Model {}
|
interface ISequelizeModel extends InstanceType<ModelStatic<Model>> {}
|
||||||
|
|
||||||
interface ISequelizeModels {
|
interface ISequelizeModels {
|
||||||
[prop: string]: ISequelizeModel;
|
[prop: string]: ISequelizeModel;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ISequelizeModel extends Model {
|
interface ISequelizeModel extends Model {
|
||||||
associate?: (connection: Sequelize, models?: ISequelizeModels) => void;
|
associate?: (connection: Sequelize, models?: ISequelizeModels) => void;
|
||||||
hooks?: (connection: Sequelize) => void;
|
hooks?: (connection: Sequelize) => void;
|
||||||
|
|||||||
@ -86,10 +86,6 @@ export abstract class SequelizeRepository<T> implements IRepository<T> {
|
|||||||
queryCriteria,
|
queryCriteria,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!_model) {
|
|
||||||
throw new Error(`[SequelizeRepository] Model ${modelName} not found!`);
|
|
||||||
}
|
|
||||||
|
|
||||||
const args = {
|
const args = {
|
||||||
...query,
|
...query,
|
||||||
distinct: true,
|
distinct: true,
|
||||||
@ -110,7 +106,7 @@ export abstract class SequelizeRepository<T> implements IRepository<T> {
|
|||||||
value: any,
|
value: any,
|
||||||
params: any = {},
|
params: any = {},
|
||||||
): Promise<boolean> {
|
): Promise<boolean> {
|
||||||
const _model = this.adapter.getModel(modelName);
|
const _model = this.adapter.getModel(modelName) as ModelDefined<any, any>;
|
||||||
const where = {};
|
const where = {};
|
||||||
where[field] = value;
|
where[field] = value;
|
||||||
|
|
||||||
|
|||||||
@ -2,19 +2,21 @@ import {
|
|||||||
IUseCase,
|
IUseCase,
|
||||||
IUseCaseError,
|
IUseCaseError,
|
||||||
UseCaseError,
|
UseCaseError,
|
||||||
handleUseCaseError,
|
|
||||||
} from "@/contexts/common/application";
|
} from "@/contexts/common/application";
|
||||||
import { IRepositoryManager } from "@/contexts/common/domain";
|
import { IRepositoryManager } from "@/contexts/common/domain";
|
||||||
|
import { IInfrastructureError } from "@/contexts/common/infrastructure";
|
||||||
import { ISequelizeAdapter } from "@/contexts/common/infrastructure/sequelize";
|
import { ISequelizeAdapter } from "@/contexts/common/infrastructure/sequelize";
|
||||||
import {
|
import {
|
||||||
|
DomainError,
|
||||||
Email,
|
Email,
|
||||||
ICreateUser_Request_DTO,
|
ICreateUser_Request_DTO,
|
||||||
IDomainError,
|
IDomainError,
|
||||||
Name,
|
Name,
|
||||||
|
Password,
|
||||||
Result,
|
Result,
|
||||||
UniqueID,
|
UniqueID,
|
||||||
|
ensureEmailIsValid,
|
||||||
ensureIdIsValid,
|
ensureIdIsValid,
|
||||||
ensureUserEmailIsValid,
|
|
||||||
} from "@shared/contexts";
|
} from "@shared/contexts";
|
||||||
import { IUserRepository, User } from "../domain";
|
import { IUserRepository, User } from "../domain";
|
||||||
import { existsUserByEmail, existsUserByID } from "./userServices";
|
import { existsUserByEmail, existsUserByID } from "./userServices";
|
||||||
@ -38,27 +40,20 @@ export class CreateUserUseCase
|
|||||||
this._repositoryManager = props.repositoryManager;
|
this._repositoryManager = props.repositoryManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
private getRepositoryByName<T>(name: string) {
|
async execute(request: ICreateUser_Request_DTO) {
|
||||||
return this._repositoryManager.getRepository<T>(name);
|
const { id, email } = request;
|
||||||
}
|
|
||||||
|
|
||||||
async execute(
|
const userRepository = this._getUserRepository();
|
||||||
request: ICreateUser_Request_DTO,
|
|
||||||
): Promise<CreateUserResponseOrError> {
|
|
||||||
const userDTO = request;
|
|
||||||
|
|
||||||
const userRepository = this.getRepositoryByName<IUserRepository>("User");
|
|
||||||
|
|
||||||
// Validaciones de datos
|
// Validaciones de datos
|
||||||
|
|
||||||
const userIdOrError = ensureIdIsValid(userDTO.id);
|
const userIdOrError = ensureIdIsValid(id);
|
||||||
if (userIdOrError.isFailure) {
|
if (userIdOrError.isFailure) {
|
||||||
|
const message = userIdOrError.error.message; //`User ID ${userDTO.id} is not valid`;
|
||||||
return Result.fail(
|
return Result.fail(
|
||||||
handleUseCaseError(
|
UseCaseError.create(UseCaseError.INVALID_INPUT_DATA, message, [
|
||||||
UseCaseError.INVALID_INPUT_DATA,
|
{ path: "id" },
|
||||||
"User ID is not valid",
|
]),
|
||||||
userIdOrError.error,
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -68,19 +63,18 @@ export class CreateUserUseCase
|
|||||||
userRepository,
|
userRepository,
|
||||||
);
|
);
|
||||||
if (idExists) {
|
if (idExists) {
|
||||||
|
const message = `Another user with ID ${id} exists`;
|
||||||
return Result.fail(
|
return Result.fail(
|
||||||
handleUseCaseError(
|
UseCaseError.create(UseCaseError.RESOURCE_ALREADY_EXITS, message, {
|
||||||
UseCaseError.RESOURCE_ALREADY_EXITS,
|
path: "id",
|
||||||
`Another user with ID ${userDTO.id} exists`,
|
}),
|
||||||
userIdOrError.error,
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const emailOrError = ensureUserEmailIsValid(userDTO.email);
|
const emailOrError = ensureEmailIsValid(email);
|
||||||
if (emailOrError.isFailure) {
|
if (emailOrError.isFailure) {
|
||||||
return Result.fail(
|
return Result.fail(
|
||||||
handleUseCaseError(
|
UseCaseError.create(
|
||||||
UseCaseError.INVALID_INPUT_DATA,
|
UseCaseError.INVALID_INPUT_DATA,
|
||||||
"Email or password is not valid",
|
"Email or password is not valid",
|
||||||
emailOrError.error,
|
emailOrError.error,
|
||||||
@ -96,17 +90,17 @@ export class CreateUserUseCase
|
|||||||
|
|
||||||
if (emailExists) {
|
if (emailExists) {
|
||||||
return Result.fail(
|
return Result.fail(
|
||||||
handleUseCaseError(
|
UseCaseError.create(
|
||||||
UseCaseError.RESOURCE_ALREADY_EXITS,
|
UseCaseError.RESOURCE_ALREADY_EXITS,
|
||||||
`Another user with email ${userDTO.email} exists`,
|
`Another user with email ${email} exists`,
|
||||||
userIdOrError.error,
|
{ path: "email" },
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Crear user
|
// Crear user
|
||||||
const userOrError = this.tryCreateUserInstance(
|
const userOrError = this._tryCreateUserInstance(
|
||||||
userDTO,
|
request,
|
||||||
userIdOrError.object,
|
userIdOrError.object,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -116,42 +110,50 @@ export class CreateUserUseCase
|
|||||||
let message = "";
|
let message = "";
|
||||||
|
|
||||||
switch (domainError.code) {
|
switch (domainError.code) {
|
||||||
case User.ERROR_CUSTOMER_WITHOUT_NAME:
|
case User.ERROR_USER_WITHOUT_NAME:
|
||||||
return handleInvalidInputDataFailure(
|
return Result.fail(
|
||||||
"El usuario debe ser una compañía o tener nombre y apellidos.",
|
UseCaseError.create(
|
||||||
domainError,
|
UseCaseError.INVALID_INPUT_DATA,
|
||||||
|
"El usuario debe tener un nombre.",
|
||||||
|
domainError,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DomainError.INVALID_INPUT_DATA:
|
case DomainError.INVALID_INPUT_DATA:
|
||||||
errorCode = UseCaseError.INVALID_INPUT_DATA;
|
errorCode = UseCaseError.INVALID_INPUT_DATA;
|
||||||
message = domainError.message;
|
message = domainError.message;
|
||||||
return handleInvalidInputDataFailure(
|
return Result.fail(
|
||||||
"El usuario debe ser una compañía o tener nombre y apellidos.",
|
UseCaseError.create(
|
||||||
domainError,
|
UseCaseError.INVALID_INPUT_DATA,
|
||||||
|
"El usuario tiene algún dato erróneo.",
|
||||||
|
domainError,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
errorCode = UseCaseError.UNEXCEPTED_ERROR;
|
errorCode = UseCaseError.UNEXCEPTED_ERROR;
|
||||||
message = domainError.message;
|
message = domainError.message;
|
||||||
return handleUseCaseError(errorCode, message, domainError);
|
return Result.fail(
|
||||||
|
UseCaseError.create(errorCode, message, domainError),
|
||||||
|
);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.saveUser(userOrError.object);
|
return this._saveUser(userOrError.object);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async saveUser(user: User) {
|
private async _saveUser(user: User) {
|
||||||
// Guardar el contacto
|
// Guardar el contacto
|
||||||
const transaction = this._adapter.startTransaction();
|
const transaction = this._adapter.startTransaction();
|
||||||
const userRepoBuilder = this.getRepositoryByName<IUserRepository>("User");
|
const userRepository = this._getUserRepository();
|
||||||
let userRepo: IUserRepository;
|
let userRepo: IUserRepository;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await transaction.complete(async (t) => {
|
await transaction.complete(async (t) => {
|
||||||
userRepo = userRepoBuilder({ transaction: t });
|
userRepo = userRepository({ transaction: t });
|
||||||
await userRepo.create(user);
|
await userRepo.create(user);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -159,16 +161,12 @@ export class CreateUserUseCase
|
|||||||
} catch (error: unknown) {
|
} catch (error: unknown) {
|
||||||
const _error = error as IInfrastructureError;
|
const _error = error as IInfrastructureError;
|
||||||
return Result.fail(
|
return Result.fail(
|
||||||
handleUseCaseError(
|
UseCaseError.create(UseCaseError.REPOSITORY_ERROR, _error.message),
|
||||||
UseCaseError.REPOSITORY_ERROR,
|
|
||||||
"Error al guardar el usuario",
|
|
||||||
_error,
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private tryCreateUserInstance(
|
private _tryCreateUserInstance(
|
||||||
userDTO: ICreateUser_Request_DTO,
|
userDTO: ICreateUser_Request_DTO,
|
||||||
userId: UniqueID,
|
userId: UniqueID,
|
||||||
): Result<User, IDomainError> {
|
): Result<User, IDomainError> {
|
||||||
@ -182,12 +180,22 @@ export class CreateUserUseCase
|
|||||||
return Result.fail(emailOrError.error);
|
return Result.fail(emailOrError.error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const passwordOrError = Password.createFromPlainText(userDTO.password);
|
||||||
|
if (passwordOrError.isFailure) {
|
||||||
|
return Result.fail(passwordOrError.error);
|
||||||
|
}
|
||||||
|
|
||||||
return User.create(
|
return User.create(
|
||||||
{
|
{
|
||||||
name: nameOrError.object,
|
name: nameOrError.object,
|
||||||
email: emailOrError.object,
|
email: emailOrError.object,
|
||||||
|
password: passwordOrError.object,
|
||||||
},
|
},
|
||||||
userId,
|
userId,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private _getUserRepository() {
|
||||||
|
return this._repositoryManager.getRepository<IUserRepository>("User");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,7 +3,6 @@ import {
|
|||||||
IUseCaseError,
|
IUseCaseError,
|
||||||
IUseCaseRequest,
|
IUseCaseRequest,
|
||||||
UseCaseError,
|
UseCaseError,
|
||||||
handleUseCaseError,
|
|
||||||
} from "@/contexts/common/application/useCases";
|
} from "@/contexts/common/application/useCases";
|
||||||
import { IRepositoryManager } from "@/contexts/common/domain";
|
import { IRepositoryManager } from "@/contexts/common/domain";
|
||||||
import { ISequelizeAdapter } from "@/contexts/common/infrastructure/sequelize";
|
import { ISequelizeAdapter } from "@/contexts/common/infrastructure/sequelize";
|
||||||
@ -55,7 +54,7 @@ export class DeleteUserUseCase
|
|||||||
} catch (error: unknown) {
|
} catch (error: unknown) {
|
||||||
//const _error = error as IInfrastructureError;
|
//const _error = error as IInfrastructureError;
|
||||||
return Result.fail(
|
return Result.fail(
|
||||||
handleUseCaseError(
|
UseCaseError.create(
|
||||||
UseCaseError.REPOSITORY_ERROR,
|
UseCaseError.REPOSITORY_ERROR,
|
||||||
"Error al eliminar el usuario",
|
"Error al eliminar el usuario",
|
||||||
),
|
),
|
||||||
|
|||||||
@ -3,7 +3,6 @@ import {
|
|||||||
IUseCaseError,
|
IUseCaseError,
|
||||||
IUseCaseRequest,
|
IUseCaseRequest,
|
||||||
UseCaseError,
|
UseCaseError,
|
||||||
handleUseCaseError,
|
|
||||||
} from "@/contexts/common/application/useCases";
|
} from "@/contexts/common/application/useCases";
|
||||||
import { IRepositoryManager } from "@/contexts/common/domain";
|
import { IRepositoryManager } from "@/contexts/common/domain";
|
||||||
import { ISequelizeAdapter } from "@/contexts/common/infrastructure/sequelize";
|
import { ISequelizeAdapter } from "@/contexts/common/infrastructure/sequelize";
|
||||||
@ -64,7 +63,7 @@ export class GetUserUseCase
|
|||||||
|
|
||||||
if (!user) {
|
if (!user) {
|
||||||
return Result.fail(
|
return Result.fail(
|
||||||
handleUseCaseError(UseCaseError.NOT_FOUND_ERROR, "User not found"),
|
UseCaseError.create(UseCaseError.NOT_FOUND_ERROR, "User not found"),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -72,7 +71,7 @@ export class GetUserUseCase
|
|||||||
} catch (error: unknown) {
|
} catch (error: unknown) {
|
||||||
const _error = error as IInfrastructureError;
|
const _error = error as IInfrastructureError;
|
||||||
return Result.fail(
|
return Result.fail(
|
||||||
handleUseCaseError(
|
UseCaseError.create(
|
||||||
UseCaseError.REPOSITORY_ERROR,
|
UseCaseError.REPOSITORY_ERROR,
|
||||||
"Error al consultar el usuario",
|
"Error al consultar el usuario",
|
||||||
_error,
|
_error,
|
||||||
|
|||||||
@ -2,7 +2,6 @@ import {
|
|||||||
IUseCase,
|
IUseCase,
|
||||||
IUseCaseError,
|
IUseCaseError,
|
||||||
UseCaseError,
|
UseCaseError,
|
||||||
handleUseCaseError,
|
|
||||||
} from "@/contexts/common/application/useCases";
|
} from "@/contexts/common/application/useCases";
|
||||||
import { IRepositoryManager } from "@/contexts/common/domain";
|
import { IRepositoryManager } from "@/contexts/common/domain";
|
||||||
import {
|
import {
|
||||||
@ -65,7 +64,7 @@ export class ListUsersUseCase
|
|||||||
} catch (error: unknown) {
|
} catch (error: unknown) {
|
||||||
const _error = error as IInfrastructureError;
|
const _error = error as IInfrastructureError;
|
||||||
return Result.fail(
|
return Result.fail(
|
||||||
handleUseCaseError(
|
UseCaseError.create(
|
||||||
UseCaseError.REPOSITORY_ERROR,
|
UseCaseError.REPOSITORY_ERROR,
|
||||||
"Error al listar los usurios",
|
"Error al listar los usurios",
|
||||||
_error,
|
_error,
|
||||||
|
|||||||
@ -3,7 +3,6 @@ import {
|
|||||||
IUseCaseError,
|
IUseCaseError,
|
||||||
IUseCaseRequest,
|
IUseCaseRequest,
|
||||||
UseCaseError,
|
UseCaseError,
|
||||||
handleUseCaseError,
|
|
||||||
} from "@/contexts/common/application/useCases";
|
} from "@/contexts/common/application/useCases";
|
||||||
import { IRepositoryManager } from "@/contexts/common/domain";
|
import { IRepositoryManager } from "@/contexts/common/domain";
|
||||||
import { ISequelizeAdapter } from "@/contexts/common/infrastructure/sequelize";
|
import { ISequelizeAdapter } from "@/contexts/common/infrastructure/sequelize";
|
||||||
@ -15,6 +14,7 @@ import {
|
|||||||
DomainError,
|
DomainError,
|
||||||
IDomainError,
|
IDomainError,
|
||||||
IUpdateUser_DTO,
|
IUpdateUser_DTO,
|
||||||
|
IUpdateUser_Request_DTO,
|
||||||
Note,
|
Note,
|
||||||
PostalCode,
|
PostalCode,
|
||||||
Province,
|
Province,
|
||||||
@ -27,6 +27,7 @@ import {
|
|||||||
UserName,
|
UserName,
|
||||||
UserPhone,
|
UserPhone,
|
||||||
UserTIN,
|
UserTIN,
|
||||||
|
ensureIdIsValid,
|
||||||
} from "@shared/contexts";
|
} from "@shared/contexts";
|
||||||
|
|
||||||
import { IInfrastructureError } from "@/contexts/common/infrastructure";
|
import { IInfrastructureError } from "@/contexts/common/infrastructure";
|
||||||
@ -40,10 +41,11 @@ import {
|
|||||||
UserAddressType,
|
UserAddressType,
|
||||||
UserShippingAddress,
|
UserShippingAddress,
|
||||||
} from "../domain";
|
} from "../domain";
|
||||||
|
import { existsUserByID } from "./userServices";
|
||||||
|
|
||||||
export interface IUpdateUserUseCaseRequest extends IUseCaseRequest {
|
export interface IUpdateUserUseCaseRequest extends IUseCaseRequest {
|
||||||
id: UniqueID;
|
id: UniqueID;
|
||||||
userDTO: IUpdateUser_DTO;
|
userDTO: IUpdateUser_Request_DTO;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type UpdateUserResponseOrError =
|
export type UpdateUserResponseOrError =
|
||||||
@ -73,13 +75,30 @@ export class UpdateUserUseCase
|
|||||||
request: IUpdateUserUseCaseRequest,
|
request: IUpdateUserUseCaseRequest,
|
||||||
): Promise<UpdateUserResponseOrError> {
|
): Promise<UpdateUserResponseOrError> {
|
||||||
const { id, userDTO } = request;
|
const { id, userDTO } = request;
|
||||||
|
const userRepository = this.getRepositoryByName<IUserRepository>("User");
|
||||||
|
|
||||||
|
// Validaciones de datos
|
||||||
|
const userIdOrError = ensureIdIsValid(userDTO.id);
|
||||||
|
if (userIdOrError.isFailure) {
|
||||||
|
return Result.fail(
|
||||||
|
UseCaseError.create(
|
||||||
|
UseCaseError.INVALID_INPUT_DATA,
|
||||||
|
"User ID is not valid",
|
||||||
|
userIdOrError.error,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// Comprobar que existe el user
|
// Comprobar que existe el user
|
||||||
const idExists = await this._findUserID(id);
|
const idExists = await existsUserByID(
|
||||||
|
userIdOrError.object,
|
||||||
|
this._adapter,
|
||||||
|
userRepository,
|
||||||
|
);
|
||||||
if (!idExists) {
|
if (!idExists) {
|
||||||
const message = `User with ID ${id.toString()} not found`;
|
const message = `User with ID ${id.toString()} not found`;
|
||||||
return Result.fail<IUseCaseError>(
|
return Result.fail<IUseCaseError>(
|
||||||
handleUseCaseError(UseCaseError.NOT_FOUND_ERROR, message, [
|
UseCaseError.create(UseCaseError.NOT_FOUND_ERROR, message, [
|
||||||
{ path: "id" },
|
{ path: "id" },
|
||||||
]),
|
]),
|
||||||
);
|
);
|
||||||
@ -117,7 +136,7 @@ export class UpdateUserUseCase
|
|||||||
}
|
}
|
||||||
|
|
||||||
return Result.fail<IUseCaseError>(
|
return Result.fail<IUseCaseError>(
|
||||||
handleUseCaseError(errorCode, message, payload),
|
UseCaseError.create(errorCode, message, payload),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -326,7 +345,7 @@ export class UpdateUserUseCase
|
|||||||
} catch (error: unknown) {
|
} catch (error: unknown) {
|
||||||
const _error = error as IInfrastructureError;
|
const _error = error as IInfrastructureError;
|
||||||
return Result.fail(
|
return Result.fail(
|
||||||
handleUseCaseError(
|
UseCaseError.create(
|
||||||
UseCaseError.REPOSITORY_ERROR,
|
UseCaseError.REPOSITORY_ERROR,
|
||||||
"Error al guardar el usuario",
|
"Error al guardar el usuario",
|
||||||
_error,
|
_error,
|
||||||
|
|||||||
@ -0,0 +1,9 @@
|
|||||||
|
import { CompositeSpecification } from "@/contexts/common/domain";
|
||||||
|
|
||||||
|
import { User } from "./User";
|
||||||
|
|
||||||
|
export class UserHasName extends CompositeSpecification<User> {
|
||||||
|
public isSatisfiedBy(candidate: User): boolean {
|
||||||
|
return !candidate.name.isEmpty();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -5,22 +5,25 @@ import {
|
|||||||
Email,
|
Email,
|
||||||
IDomainError,
|
IDomainError,
|
||||||
Name,
|
Name,
|
||||||
|
Password,
|
||||||
Result,
|
Result,
|
||||||
UniqueID,
|
UniqueID,
|
||||||
|
handleDomainError,
|
||||||
} from "@shared/contexts";
|
} from "@shared/contexts";
|
||||||
|
import { UserHasName } from "./User.specifications";
|
||||||
|
|
||||||
export interface IUserProps {
|
export interface IUserProps {
|
||||||
name: Name;
|
name: Name;
|
||||||
email: Email;
|
email: Email;
|
||||||
password?: string;
|
password: Password;
|
||||||
hashed_password?: string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//type ISecuredUserProps = Omit<IUserProps, "password">;
|
||||||
|
|
||||||
export interface IUser {
|
export interface IUser {
|
||||||
id: UniqueID;
|
id: UniqueID;
|
||||||
name: Name;
|
name: Name;
|
||||||
email: Email;
|
email: Email;
|
||||||
hashed_password: string;
|
|
||||||
isUser: boolean;
|
isUser: boolean;
|
||||||
isAdmin: boolean;
|
isAdmin: boolean;
|
||||||
|
|
||||||
@ -28,33 +31,29 @@ export interface IUser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class User extends AggregateRoot<IUserProps> implements IUser {
|
export class User extends AggregateRoot<IUserProps> implements IUser {
|
||||||
|
static readonly ERROR_USER_WITHOUT_NAME = "ERROR_USER_WITHOUT_NAME";
|
||||||
|
|
||||||
public static create(
|
public static create(
|
||||||
props: IUserProps,
|
props: IUserProps,
|
||||||
id?: UniqueID,
|
id?: UniqueID,
|
||||||
): Result<User, IDomainError> {
|
): Result<User, IDomainError> {
|
||||||
//const isNew = !!id === false;
|
|
||||||
|
|
||||||
// Se hace en el constructor de la Entidad
|
|
||||||
/* if (isNew) {
|
|
||||||
id = UniqueEntityID.create();
|
|
||||||
}*/
|
|
||||||
|
|
||||||
const user = new User(props, id);
|
const user = new User(props, id);
|
||||||
|
|
||||||
|
// Reglas de negocio / validaciones
|
||||||
|
const isValidUser = new UserHasName().isSatisfiedBy(user);
|
||||||
|
|
||||||
|
if (!isValidUser) {
|
||||||
|
return Result.fail(handleDomainError(User.ERROR_USER_WITHOUT_NAME));
|
||||||
|
}
|
||||||
|
|
||||||
return Result.ok<User>(user);
|
return Result.ok<User>(user);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async hashPassword(password): Promise<string> {
|
public static async hashPassword(password): Promise<string> {
|
||||||
return hashPassword(password, await genSalt());
|
return Password.hashPassword(password);
|
||||||
}
|
}
|
||||||
|
|
||||||
private _hashed_password: string;
|
private _password: string;
|
||||||
|
|
||||||
private constructor(props: IUserProps, id?: UniqueID) {
|
|
||||||
super({ ...props, password: "", hashed_password: "" }, id);
|
|
||||||
|
|
||||||
this._protectPassword(props);
|
|
||||||
}
|
|
||||||
|
|
||||||
get name(): Name {
|
get name(): Name {
|
||||||
return this.props.name;
|
return this.props.name;
|
||||||
@ -65,7 +64,7 @@ export class User extends AggregateRoot<IUserProps> implements IUser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
get hashed_password(): string {
|
get hashed_password(): string {
|
||||||
return this._hashed_password;
|
return this._password;
|
||||||
}
|
}
|
||||||
|
|
||||||
get isUser(): boolean {
|
get isUser(): boolean {
|
||||||
@ -77,17 +76,7 @@ export class User extends AggregateRoot<IUserProps> implements IUser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public verifyPassword(candidatePassword: string): boolean {
|
public verifyPassword(candidatePassword: string): boolean {
|
||||||
return bCrypt.compareSync(candidatePassword, this._hashed_password!);
|
return bCrypt.compareSync(candidatePassword, this._password!);
|
||||||
}
|
|
||||||
|
|
||||||
private async _protectPassword(props: IUserProps) {
|
|
||||||
const { password, hashed_password } = props;
|
|
||||||
|
|
||||||
if (password) {
|
|
||||||
this._hashed_password = await User.hashPassword(password);
|
|
||||||
} else {
|
|
||||||
this._hashed_password = hashed_password!;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -108,5 +97,3 @@ async function hashPassword(password: string, salt: string): Promise<string> {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
User.hashPassword("123456").then((value) => console.log(value));
|
|
||||||
|
|||||||
@ -3,6 +3,9 @@ import { Email, ICollection, IQueryCriteria, UniqueID } from "@shared/contexts";
|
|||||||
import { User } from "../entities";
|
import { User } from "../entities";
|
||||||
|
|
||||||
export interface IUserRepository extends IRepository<any> {
|
export interface IUserRepository extends IRepository<any> {
|
||||||
|
create(user: User): Promise<void>;
|
||||||
|
update(user: User): Promise<void>;
|
||||||
|
|
||||||
getById(id: UniqueID): Promise<User | null>;
|
getById(id: UniqueID): Promise<User | null>;
|
||||||
findUserByEmail(email: Email): Promise<User | null>;
|
findUserByEmail(email: Email): Promise<User | null>;
|
||||||
findAll(queryCriteria?: IQueryCriteria): Promise<ICollection<User>>;
|
findAll(queryCriteria?: IQueryCriteria): Promise<ICollection<User>>;
|
||||||
|
|||||||
@ -30,6 +30,20 @@ export class UserRepository
|
|||||||
this.mapper = mapper;
|
this.mapper = mapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async create(user: User): Promise<void> {
|
||||||
|
const userData = this.mapper.mapToPersistence(user);
|
||||||
|
await this._save("User_Model", user.id, userData);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async update(user: User): Promise<void> {
|
||||||
|
const userData = this.mapper.mapToPersistence(user);
|
||||||
|
|
||||||
|
// borrando y luego creando
|
||||||
|
await this.removeById(user.id, true);
|
||||||
|
|
||||||
|
await this._save("User_Model", user.id, userData, {});
|
||||||
|
}
|
||||||
|
|
||||||
public async getById(id: UniqueID): Promise<User | null> {
|
public async getById(id: UniqueID): Promise<User | null> {
|
||||||
const rawUser: any = await this._getById("User_Model", id);
|
const rawUser: any = await this._getById("User_Model", id);
|
||||||
|
|
||||||
|
|||||||
@ -3,13 +3,9 @@ import { IServerError } from "@/contexts/common/domain/errors";
|
|||||||
import {
|
import {
|
||||||
IInfrastructureError,
|
IInfrastructureError,
|
||||||
InfrastructureError,
|
InfrastructureError,
|
||||||
handleInfrastructureError,
|
|
||||||
} from "@/contexts/common/infrastructure";
|
} from "@/contexts/common/infrastructure";
|
||||||
import { ExpressController } from "@/contexts/common/infrastructure/express";
|
import { ExpressController } from "@/contexts/common/infrastructure/express";
|
||||||
import {
|
import { CreateUserUseCase } from "@/contexts/users/application";
|
||||||
CreateUserResponseOrError,
|
|
||||||
CreateUserUseCase,
|
|
||||||
} from "@/contexts/users/application";
|
|
||||||
import { User } from "@/contexts/users/domain";
|
import { User } from "@/contexts/users/domain";
|
||||||
import {
|
import {
|
||||||
ICreateUser_Request_DTO,
|
ICreateUser_Request_DTO,
|
||||||
@ -48,7 +44,7 @@ export class CreateUserController extends ExpressController {
|
|||||||
|
|
||||||
if (userDTOOrError.isFailure) {
|
if (userDTOOrError.isFailure) {
|
||||||
const errorMessage = "User data not valid";
|
const errorMessage = "User data not valid";
|
||||||
const infraError = handleInfrastructureError(
|
const infraError = InfrastructureError.create(
|
||||||
InfrastructureError.INVALID_INPUT_DATA,
|
InfrastructureError.INVALID_INPUT_DATA,
|
||||||
errorMessage,
|
errorMessage,
|
||||||
userDTOOrError.error,
|
userDTOOrError.error,
|
||||||
@ -57,9 +53,7 @@ export class CreateUserController extends ExpressController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Llamar al caso de uso
|
// Llamar al caso de uso
|
||||||
const result: CreateUserResponseOrError = await this.useCase.execute(
|
const result = await this.useCase.execute(userDTO);
|
||||||
userDTO,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (result.isFailure) {
|
if (result.isFailure) {
|
||||||
return this._handleExecuteError(result.error);
|
return this._handleExecuteError(result.error);
|
||||||
@ -82,7 +76,7 @@ export class CreateUserController extends ExpressController {
|
|||||||
switch (error.code) {
|
switch (error.code) {
|
||||||
case UseCaseError.INVALID_INPUT_DATA:
|
case UseCaseError.INVALID_INPUT_DATA:
|
||||||
errorMessage = "User data not valid";
|
errorMessage = "User data not valid";
|
||||||
infraError = handleInfrastructureError(
|
infraError = InfrastructureError.create(
|
||||||
InfrastructureError.INVALID_INPUT_DATA,
|
InfrastructureError.INVALID_INPUT_DATA,
|
||||||
errorMessage,
|
errorMessage,
|
||||||
error,
|
error,
|
||||||
@ -93,18 +87,28 @@ export class CreateUserController extends ExpressController {
|
|||||||
case UseCaseError.RESOURCE_ALREADY_EXITS:
|
case UseCaseError.RESOURCE_ALREADY_EXITS:
|
||||||
errorMessage = "User already exists";
|
errorMessage = "User already exists";
|
||||||
|
|
||||||
infraError = handleInfrastructureError(
|
infraError = InfrastructureError.create(
|
||||||
InfrastructureError.INVALID_INPUT_DATA,
|
InfrastructureError.RESOURCE_ALREADY_REGISTERED,
|
||||||
errorMessage,
|
errorMessage,
|
||||||
error,
|
error,
|
||||||
);
|
);
|
||||||
return this.conflictError(error.message, error);
|
return this.conflictError(errorMessage, infraError);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case UseCaseError.REPOSITORY_ERROR:
|
||||||
|
errorMessage = "Error saving user";
|
||||||
|
infraError = InfrastructureError.create(
|
||||||
|
InfrastructureError.UNEXCEPTED_ERROR,
|
||||||
|
errorMessage,
|
||||||
|
error,
|
||||||
|
);
|
||||||
|
return this.conflictError(errorMessage, infraError);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case UseCaseError.UNEXCEPTED_ERROR:
|
case UseCaseError.UNEXCEPTED_ERROR:
|
||||||
errorMessage = error.message;
|
errorMessage = error.message;
|
||||||
|
|
||||||
infraError = handleInfrastructureError(
|
infraError = InfrastructureError.create(
|
||||||
InfrastructureError.UNEXCEPTED_ERROR,
|
InfrastructureError.UNEXCEPTED_ERROR,
|
||||||
errorMessage,
|
errorMessage,
|
||||||
error,
|
error,
|
||||||
|
|||||||
@ -6,7 +6,6 @@ import { IServerError } from "@/contexts/common/domain/errors";
|
|||||||
import {
|
import {
|
||||||
IInfrastructureError,
|
IInfrastructureError,
|
||||||
InfrastructureError,
|
InfrastructureError,
|
||||||
handleInfrastructureError,
|
|
||||||
} from "@/contexts/common/infrastructure";
|
} from "@/contexts/common/infrastructure";
|
||||||
import { ExpressController } from "@/contexts/common/infrastructure/express";
|
import { ExpressController } from "@/contexts/common/infrastructure/express";
|
||||||
import { DeleteUserUseCase } from "@/contexts/users/application";
|
import { DeleteUserUseCase } from "@/contexts/users/application";
|
||||||
@ -33,7 +32,7 @@ export class DeleteUserController extends ExpressController {
|
|||||||
const userIdOrError = ensureIdIsValid(userId);
|
const userIdOrError = ensureIdIsValid(userId);
|
||||||
if (userIdOrError.isFailure) {
|
if (userIdOrError.isFailure) {
|
||||||
const errorMessage = "User ID is not valid";
|
const errorMessage = "User ID is not valid";
|
||||||
const infraError = handleInfrastructureError(
|
const infraError = InfrastructureError.create(
|
||||||
InfrastructureError.INVALID_INPUT_DATA,
|
InfrastructureError.INVALID_INPUT_DATA,
|
||||||
errorMessage,
|
errorMessage,
|
||||||
userIdOrError.error,
|
userIdOrError.error,
|
||||||
@ -63,7 +62,7 @@ export class DeleteUserController extends ExpressController {
|
|||||||
case UseCaseError.NOT_FOUND_ERROR:
|
case UseCaseError.NOT_FOUND_ERROR:
|
||||||
errorMessage = "User not found";
|
errorMessage = "User not found";
|
||||||
|
|
||||||
infraError = handleInfrastructureError(
|
infraError = InfrastructureError.create(
|
||||||
InfrastructureError.RESOURCE_NOT_FOUND_ERROR,
|
InfrastructureError.RESOURCE_NOT_FOUND_ERROR,
|
||||||
errorMessage,
|
errorMessage,
|
||||||
error,
|
error,
|
||||||
@ -75,7 +74,7 @@ export class DeleteUserController extends ExpressController {
|
|||||||
case UseCaseError.UNEXCEPTED_ERROR:
|
case UseCaseError.UNEXCEPTED_ERROR:
|
||||||
errorMessage = error.message;
|
errorMessage = error.message;
|
||||||
|
|
||||||
infraError = handleInfrastructureError(
|
infraError = InfrastructureError.create(
|
||||||
InfrastructureError.UNEXCEPTED_ERROR,
|
InfrastructureError.UNEXCEPTED_ERROR,
|
||||||
errorMessage,
|
errorMessage,
|
||||||
error,
|
error,
|
||||||
|
|||||||
@ -11,7 +11,6 @@ import { IServerError } from "@/contexts/common/domain/errors";
|
|||||||
import {
|
import {
|
||||||
IInfrastructureError,
|
IInfrastructureError,
|
||||||
InfrastructureError,
|
InfrastructureError,
|
||||||
handleInfrastructureError,
|
|
||||||
} from "@/contexts/common/infrastructure";
|
} from "@/contexts/common/infrastructure";
|
||||||
import { IUserContext } from "../../../User.context";
|
import { IUserContext } from "../../../User.context";
|
||||||
import { IGetUserPresenter } from "./presenter";
|
import { IGetUserPresenter } from "./presenter";
|
||||||
@ -43,7 +42,7 @@ export class GetUserController extends ExpressController {
|
|||||||
const userIdOrError = ensureIdIsValid(userId);
|
const userIdOrError = ensureIdIsValid(userId);
|
||||||
if (userIdOrError.isFailure) {
|
if (userIdOrError.isFailure) {
|
||||||
const errorMessage = "User ID is not valid";
|
const errorMessage = "User ID is not valid";
|
||||||
const infraError = handleInfrastructureError(
|
const infraError = InfrastructureError.create(
|
||||||
InfrastructureError.INVALID_INPUT_DATA,
|
InfrastructureError.INVALID_INPUT_DATA,
|
||||||
errorMessage,
|
errorMessage,
|
||||||
userIdOrError.error,
|
userIdOrError.error,
|
||||||
@ -78,7 +77,7 @@ export class GetUserController extends ExpressController {
|
|||||||
case UseCaseError.NOT_FOUND_ERROR:
|
case UseCaseError.NOT_FOUND_ERROR:
|
||||||
errorMessage = "User not found";
|
errorMessage = "User not found";
|
||||||
|
|
||||||
infraError = handleInfrastructureError(
|
infraError = InfrastructureError.create(
|
||||||
InfrastructureError.RESOURCE_NOT_FOUND_ERROR,
|
InfrastructureError.RESOURCE_NOT_FOUND_ERROR,
|
||||||
errorMessage,
|
errorMessage,
|
||||||
error,
|
error,
|
||||||
@ -90,7 +89,7 @@ export class GetUserController extends ExpressController {
|
|||||||
case UseCaseError.UNEXCEPTED_ERROR:
|
case UseCaseError.UNEXCEPTED_ERROR:
|
||||||
errorMessage = error.message;
|
errorMessage = error.message;
|
||||||
|
|
||||||
infraError = handleInfrastructureError(
|
infraError = InfrastructureError.create(
|
||||||
InfrastructureError.UNEXCEPTED_ERROR,
|
InfrastructureError.UNEXCEPTED_ERROR,
|
||||||
errorMessage,
|
errorMessage,
|
||||||
error,
|
error,
|
||||||
|
|||||||
@ -3,7 +3,6 @@ import { IServerError } from "@/contexts/common/domain/errors";
|
|||||||
import {
|
import {
|
||||||
IInfrastructureError,
|
IInfrastructureError,
|
||||||
InfrastructureError,
|
InfrastructureError,
|
||||||
handleInfrastructureError,
|
|
||||||
} from "@/contexts/common/infrastructure";
|
} from "@/contexts/common/infrastructure";
|
||||||
import { ExpressController } from "@/contexts/common/infrastructure/express";
|
import { ExpressController } from "@/contexts/common/infrastructure/express";
|
||||||
import {
|
import {
|
||||||
@ -49,7 +48,7 @@ export class UpdateUserController extends ExpressController {
|
|||||||
const userIdOrError = ensureIdIsValid(userId);
|
const userIdOrError = ensureIdIsValid(userId);
|
||||||
if (userIdOrError.isFailure) {
|
if (userIdOrError.isFailure) {
|
||||||
const errorMessage = "User ID is not valid";
|
const errorMessage = "User ID is not valid";
|
||||||
const infraError = handleInfrastructureError(
|
const infraError = InfrastructureError.create(
|
||||||
InfrastructureError.INVALID_INPUT_DATA,
|
InfrastructureError.INVALID_INPUT_DATA,
|
||||||
errorMessage,
|
errorMessage,
|
||||||
userIdOrError.error,
|
userIdOrError.error,
|
||||||
@ -62,7 +61,7 @@ export class UpdateUserController extends ExpressController {
|
|||||||
|
|
||||||
if (userDTOOrError.isFailure) {
|
if (userDTOOrError.isFailure) {
|
||||||
const errorMessage = "User data not valid";
|
const errorMessage = "User data not valid";
|
||||||
const infraError = handleInfrastructureError(
|
const infraError = InfrastructureError.create(
|
||||||
InfrastructureError.INVALID_INPUT_DATA,
|
InfrastructureError.INVALID_INPUT_DATA,
|
||||||
errorMessage,
|
errorMessage,
|
||||||
userDTOOrError.error,
|
userDTOOrError.error,
|
||||||
@ -98,7 +97,7 @@ export class UpdateUserController extends ExpressController {
|
|||||||
case UseCaseError.NOT_FOUND_ERROR:
|
case UseCaseError.NOT_FOUND_ERROR:
|
||||||
errorMessage = "User not found";
|
errorMessage = "User not found";
|
||||||
|
|
||||||
infraError = handleInfrastructureError(
|
infraError = InfrastructureError.create(
|
||||||
InfrastructureError.RESOURCE_NOT_FOUND_ERROR,
|
InfrastructureError.RESOURCE_NOT_FOUND_ERROR,
|
||||||
errorMessage,
|
errorMessage,
|
||||||
error,
|
error,
|
||||||
@ -110,7 +109,7 @@ export class UpdateUserController extends ExpressController {
|
|||||||
case UseCaseError.INVALID_INPUT_DATA:
|
case UseCaseError.INVALID_INPUT_DATA:
|
||||||
errorMessage = "User data not valid";
|
errorMessage = "User data not valid";
|
||||||
|
|
||||||
infraError = handleInfrastructureError(
|
infraError = InfrastructureError.create(
|
||||||
InfrastructureError.INVALID_INPUT_DATA,
|
InfrastructureError.INVALID_INPUT_DATA,
|
||||||
"Datos del cliente a actulizar erróneos",
|
"Datos del cliente a actulizar erróneos",
|
||||||
error,
|
error,
|
||||||
@ -121,7 +120,7 @@ export class UpdateUserController extends ExpressController {
|
|||||||
case UseCaseError.UNEXCEPTED_ERROR:
|
case UseCaseError.UNEXCEPTED_ERROR:
|
||||||
errorMessage = error.message;
|
errorMessage = error.message;
|
||||||
|
|
||||||
infraError = handleInfrastructureError(
|
infraError = InfrastructureError.create(
|
||||||
InfrastructureError.UNEXCEPTED_ERROR,
|
InfrastructureError.UNEXCEPTED_ERROR,
|
||||||
errorMessage,
|
errorMessage,
|
||||||
error,
|
error,
|
||||||
|
|||||||
@ -2,7 +2,7 @@ import {
|
|||||||
ISequelizeMapper,
|
ISequelizeMapper,
|
||||||
SequelizeMapper,
|
SequelizeMapper,
|
||||||
} from "@/contexts/common/infrastructure";
|
} from "@/contexts/common/infrastructure";
|
||||||
import { Email, Name, UniqueID } from "@shared/contexts";
|
import { Email, Name, Password, UniqueID } from "@shared/contexts";
|
||||||
import { IUserProps, User } from "../../domain";
|
import { IUserProps, User } from "../../domain";
|
||||||
import { IUserContext } from "../User.context";
|
import { IUserContext } from "../User.context";
|
||||||
import { TCreationUser_Attributes, User_Model } from "../sequelize/user.model";
|
import { TCreationUser_Attributes, User_Model } from "../sequelize/user.model";
|
||||||
@ -22,7 +22,11 @@ class UserMapper
|
|||||||
const props: IUserProps = {
|
const props: IUserProps = {
|
||||||
name: this.mapsValue(source, "name", Name.create),
|
name: this.mapsValue(source, "name", Name.create),
|
||||||
email: this.mapsValue(source, "email", Email.create),
|
email: this.mapsValue(source, "email", Email.create),
|
||||||
hashed_password: source.password,
|
password: this.mapsValue(
|
||||||
|
source,
|
||||||
|
"password",
|
||||||
|
Password.createFromHashedText,
|
||||||
|
),
|
||||||
};
|
};
|
||||||
|
|
||||||
const id = this.mapsValue(source, "id", UniqueID.create);
|
const id = this.mapsValue(source, "id", UniqueID.create);
|
||||||
@ -43,7 +47,7 @@ class UserMapper
|
|||||||
id: source.id.toPrimitive(),
|
id: source.id.toPrimitive(),
|
||||||
name: source.name.toPrimitive(),
|
name: source.name.toPrimitive(),
|
||||||
email: source.email.toPrimitive(),
|
email: source.email.toPrimitive(),
|
||||||
password: source.hashed_password,
|
password: "",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,8 @@
|
|||||||
|
import { RepositoryManager } from "@/contexts/common/domain";
|
||||||
|
import { createSequelizeAdapter } from "@/contexts/common/infrastructure/sequelize";
|
||||||
|
|
||||||
|
export const createContextMiddleware = () => ({
|
||||||
|
adapter: createSequelizeAdapter(),
|
||||||
|
repositoryManager: RepositoryManager.getInstance(),
|
||||||
|
services: {},
|
||||||
|
});
|
||||||
@ -1,9 +1,9 @@
|
|||||||
import { AuthRouter } from "@/contexts/auth";
|
import { AuthRouter } from "@/contexts/auth";
|
||||||
import { CatalogRouter } from "@/contexts/catalog";
|
import { CatalogRouter } from "@/contexts/catalog";
|
||||||
import { RepositoryManager } from "@/contexts/common/domain";
|
import { createMiddlewareMap } from "@/contexts/common/infrastructure/express";
|
||||||
import { createSequelizeAdapter } from "@/contexts/common/infrastructure/sequelize";
|
|
||||||
import { UserRouter } from "@/contexts/users";
|
import { UserRouter } from "@/contexts/users";
|
||||||
import Express from "express";
|
import Express from "express";
|
||||||
|
import { createContextMiddleware } from "./context.middleware";
|
||||||
|
|
||||||
export const v1Routes = () => {
|
export const v1Routes = () => {
|
||||||
const routes = Express.Router({ mergeParams: true });
|
const routes = Express.Router({ mergeParams: true });
|
||||||
@ -12,22 +12,14 @@ export const v1Routes = () => {
|
|||||||
res.send("Hello world!");
|
res.send("Hello world!");
|
||||||
});
|
});
|
||||||
|
|
||||||
//v1Routes.use("/auth", authRoutes);
|
|
||||||
//v1Routes.use("/catalog", catalogRoutes);
|
|
||||||
|
|
||||||
routes.use(
|
routes.use(
|
||||||
(
|
(
|
||||||
req: Express.Request,
|
req: Express.Request,
|
||||||
res: Express.Response,
|
res: Express.Response,
|
||||||
next: Express.NextFunction,
|
next: Express.NextFunction,
|
||||||
) => {
|
) => {
|
||||||
res.locals["context"] = {
|
res.locals["context"] = createContextMiddleware();
|
||||||
adapter: createSequelizeAdapter(),
|
res.locals["middlewares"] = createMiddlewareMap();
|
||||||
repositoryManager: RepositoryManager.getInstance(),
|
|
||||||
services: {},
|
|
||||||
};
|
|
||||||
|
|
||||||
res.locals["middlewares"] = new Map<string, Express.RequestHandler>();
|
|
||||||
|
|
||||||
return next();
|
return next();
|
||||||
},
|
},
|
||||||
|
|||||||
110
shared/lib/contexts/common/domain/entities/Password.ts
Normal file
110
shared/lib/contexts/common/domain/entities/Password.ts
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
import bCrypt from "bcryptjs";
|
||||||
|
|
||||||
|
import Joi from "joi";
|
||||||
|
import { UndefinedOr } from "../../../../utilities";
|
||||||
|
import { RuleValidator } from "../RuleValidator";
|
||||||
|
import { DomainError, handleDomainError } from "../errors";
|
||||||
|
import { Result } from "./Result";
|
||||||
|
import {
|
||||||
|
IStringValueObjectOptions,
|
||||||
|
StringValueObject,
|
||||||
|
} from "./StringValueObject";
|
||||||
|
|
||||||
|
export interface IPasswordOptions extends IStringValueObjectOptions {}
|
||||||
|
|
||||||
|
export class Password extends StringValueObject {
|
||||||
|
private static readonly MIN_LENGTH = 4;
|
||||||
|
private static readonly MAX_LENGTH = 255;
|
||||||
|
|
||||||
|
protected static validate(
|
||||||
|
value: UndefinedOr<string>,
|
||||||
|
options: IPasswordOptions,
|
||||||
|
) {
|
||||||
|
const rule = Joi.string()
|
||||||
|
.allow(null)
|
||||||
|
.allow("")
|
||||||
|
.default("")
|
||||||
|
.trim()
|
||||||
|
.min(Password.MIN_LENGTH)
|
||||||
|
.max(Password.MAX_LENGTH)
|
||||||
|
.label(options.label ? options.label : "value");
|
||||||
|
|
||||||
|
return RuleValidator.validate<string>(rule, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static createFromHashedText(
|
||||||
|
value: UndefinedOr<string>,
|
||||||
|
options: IPasswordOptions = {},
|
||||||
|
) {
|
||||||
|
const _options = {
|
||||||
|
label: "password",
|
||||||
|
...options,
|
||||||
|
};
|
||||||
|
|
||||||
|
const validationResult = Password.validate(value, _options);
|
||||||
|
|
||||||
|
if (validationResult.isFailure) {
|
||||||
|
return Result.fail(
|
||||||
|
handleDomainError(
|
||||||
|
DomainError.INVALID_INPUT_DATA,
|
||||||
|
validationResult.error.message,
|
||||||
|
_options,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Result.ok(new Password(validationResult.object));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async createFromPlainText(
|
||||||
|
value: UndefinedOr<string>,
|
||||||
|
options: IPasswordOptions = {},
|
||||||
|
) {
|
||||||
|
const _options = {
|
||||||
|
label: "password",
|
||||||
|
...options,
|
||||||
|
};
|
||||||
|
|
||||||
|
const validationResult = Password.validate(value, _options);
|
||||||
|
|
||||||
|
if (validationResult.isFailure) {
|
||||||
|
return Result.fail(
|
||||||
|
handleDomainError(
|
||||||
|
DomainError.INVALID_INPUT_DATA,
|
||||||
|
validationResult.error.message,
|
||||||
|
_options,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Result.ok(
|
||||||
|
new Password(await Password.hashPassword(validationResult.object)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async hashPassword(plainText: string): Promise<string> {
|
||||||
|
return hashPassword(plainText, await genSalt());
|
||||||
|
}
|
||||||
|
|
||||||
|
public verifyPassword(candidatePassword: string): boolean {
|
||||||
|
return bCrypt.compareSync(candidatePassword, this.value!);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function genSalt(rounds = 10): Promise<string> {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
bCrypt.genSalt(rounds, function (err, salt) {
|
||||||
|
if (err) return reject(err);
|
||||||
|
return resolve(salt);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function hashPassword(password: string, salt: string): Promise<string> {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
bCrypt.hash(password, salt, function (err, hash) {
|
||||||
|
if (err) return reject(err);
|
||||||
|
return resolve(hash);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
@ -11,6 +11,7 @@ export * from "./MoneyValue";
|
|||||||
export * from "./Name";
|
export * from "./Name";
|
||||||
export * from "./Note";
|
export * from "./Note";
|
||||||
export * from "./NullableValueObject";
|
export * from "./NullableValueObject";
|
||||||
|
export * from "./Password";
|
||||||
export * from "./Percentage";
|
export * from "./Percentage";
|
||||||
export * from "./Phone";
|
export * from "./Phone";
|
||||||
export * from "./Quantity";
|
export * from "./Quantity";
|
||||||
|
|||||||
@ -5,15 +5,17 @@ export interface ICreateUser_Request_DTO {
|
|||||||
id: string;
|
id: string;
|
||||||
name: string;
|
name: string;
|
||||||
email: string;
|
email: string;
|
||||||
|
password: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function ensureCreateUser_Request_DTOIsValid(
|
export function ensureCreateUser_Request_DTOIsValid(
|
||||||
userDTO: ICreateUser_Request_DTO,
|
userDTO: ICreateUser_Request_DTO,
|
||||||
): Result<boolean, Error> {
|
) {
|
||||||
const schema = Joi.object({
|
const schema = Joi.object({
|
||||||
id: Joi.string(),
|
id: Joi.string(),
|
||||||
name: Joi.string(),
|
name: Joi.string(),
|
||||||
email: Joi.string(),
|
email: Joi.string(),
|
||||||
|
password: Joi.string(),
|
||||||
}).unknown(true);
|
}).unknown(true);
|
||||||
|
|
||||||
const result = RuleValidator.validate<ICreateUser_Request_DTO>(
|
const result = RuleValidator.validate<ICreateUser_Request_DTO>(
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user