.
This commit is contained in:
parent
9264739af9
commit
173ec9e8d8
@ -79,7 +79,6 @@
|
|||||||
"remove": "^0.1.5",
|
"remove": "^0.1.5",
|
||||||
"response-time": "^2.3.2",
|
"response-time": "^2.3.2",
|
||||||
"sequelize": "^6.37.3",
|
"sequelize": "^6.37.3",
|
||||||
"sequelize-revision": "^6.0.0",
|
|
||||||
"sequelize-typescript": "^2.1.5",
|
"sequelize-typescript": "^2.1.5",
|
||||||
"shallow-equal-object": "^1.1.1",
|
"shallow-equal-object": "^1.1.1",
|
||||||
"ts-node": "^10.9.1",
|
"ts-node": "^10.9.1",
|
||||||
|
|||||||
@ -0,0 +1,88 @@
|
|||||||
|
import {
|
||||||
|
IUseCase,
|
||||||
|
IUseCaseError,
|
||||||
|
IUseCaseRequest,
|
||||||
|
UseCaseError,
|
||||||
|
handleUseCaseError,
|
||||||
|
} from "@/contexts/common/application";
|
||||||
|
import { IRepositoryManager } from "@/contexts/common/domain";
|
||||||
|
import { IInfrastructureError } from "@/contexts/common/infrastructure";
|
||||||
|
import { ISequelizeAdapter } from "@/contexts/common/infrastructure/sequelize";
|
||||||
|
import { Result, ensureUserEmailIsValid } from "@shared/contexts";
|
||||||
|
import { User } from "../domain";
|
||||||
|
import { findUserByEmail } from "./authServices";
|
||||||
|
|
||||||
|
export interface FindUserByEmailRequest extends IUseCaseRequest {
|
||||||
|
email: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type FindUserByEmailResponseOrError =
|
||||||
|
| Result<never, IUseCaseError>
|
||||||
|
| Result<User, never>;
|
||||||
|
|
||||||
|
export class FindUserByEmailUseCase
|
||||||
|
implements
|
||||||
|
IUseCase<FindUserByEmailRequest, Promise<FindUserByEmailResponseOrError>>
|
||||||
|
{
|
||||||
|
private _adapter: ISequelizeAdapter;
|
||||||
|
private _repositoryManager: IRepositoryManager;
|
||||||
|
|
||||||
|
constructor(props: {
|
||||||
|
adapter: ISequelizeAdapter;
|
||||||
|
repositoryManager: IRepositoryManager;
|
||||||
|
}) {
|
||||||
|
this._adapter = props.adapter;
|
||||||
|
this._repositoryManager = props.repositoryManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
private getRepositoryByName<T>(name: string) {
|
||||||
|
return this._repositoryManager.getRepository<T>(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
async execute(
|
||||||
|
request: FindUserByEmailRequest,
|
||||||
|
): Promise<FindUserByEmailResponseOrError> {
|
||||||
|
const { email } = request;
|
||||||
|
|
||||||
|
// Validaciones de datos
|
||||||
|
|
||||||
|
const emailOrError = ensureUserEmailIsValid(email);
|
||||||
|
if (emailOrError.isFailure) {
|
||||||
|
return Result.fail(
|
||||||
|
handleUseCaseError(
|
||||||
|
UseCaseError.INVALID_INPUT_DATA,
|
||||||
|
"Email or password is not valid",
|
||||||
|
emailOrError.error,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Crear auth
|
||||||
|
try {
|
||||||
|
const user = await findUserByEmail(
|
||||||
|
emailOrError.object,
|
||||||
|
this._adapter,
|
||||||
|
this.getRepositoryByName("Auth"),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (user === null) {
|
||||||
|
return Result.fail(
|
||||||
|
handleUseCaseError(
|
||||||
|
UseCaseError.NOT_FOUND_ERROR,
|
||||||
|
`User with email ${email} not found`,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return Result.ok<User>(user);
|
||||||
|
} catch (error: unknown) {
|
||||||
|
const _error = error as IInfrastructureError;
|
||||||
|
return Result.fail(
|
||||||
|
handleUseCaseError(
|
||||||
|
UseCaseError.REPOSITORY_ERROR,
|
||||||
|
"Error al buscar el usuario",
|
||||||
|
_error,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -7,14 +7,9 @@ import {
|
|||||||
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 {
|
import { ILogin_DTO, Result, ensureUserEmailIsValid } from "@shared/contexts";
|
||||||
Email,
|
|
||||||
ILogin_DTO,
|
|
||||||
Result,
|
|
||||||
ensureUserEmailIsValid,
|
|
||||||
} from "@shared/contexts";
|
|
||||||
import { User } from "../domain";
|
import { User } from "../domain";
|
||||||
import { IAuthRepository } from "../domain/repository";
|
import { findUserByEmail } from "./authServices";
|
||||||
|
|
||||||
export type LoginResponseOrError =
|
export type LoginResponseOrError =
|
||||||
| Result<never, IUseCaseError>
|
| Result<never, IUseCaseError>
|
||||||
@ -56,7 +51,11 @@ export class LoginUseCase
|
|||||||
|
|
||||||
// Crear auth
|
// Crear auth
|
||||||
try {
|
try {
|
||||||
const user = await this.findUserEmail(emailOrError.object);
|
const user = await findUserByEmail(
|
||||||
|
emailOrError.object,
|
||||||
|
this._adapter,
|
||||||
|
this.getRepositoryByName("Auth"),
|
||||||
|
);
|
||||||
if (user === null || !user.verifyPassword(password)) {
|
if (user === null || !user.verifyPassword(password)) {
|
||||||
return Result.fail(
|
return Result.fail(
|
||||||
handleUseCaseError(
|
handleUseCaseError(
|
||||||
@ -77,18 +76,4 @@ export class LoginUseCase
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async findUserEmail(email: Email): Promise<User | null> {
|
|
||||||
const transaction = this._adapter.startTransaction();
|
|
||||||
const authRepoBuilder = this.getRepositoryByName<IAuthRepository>("Auth");
|
|
||||||
|
|
||||||
let user: User | null = null;
|
|
||||||
|
|
||||||
await transaction.complete(async (t) => {
|
|
||||||
const authRepo = authRepoBuilder({ transaction: t });
|
|
||||||
user = await authRepo.findByEmail(email);
|
|
||||||
});
|
|
||||||
|
|
||||||
return user;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@ -0,0 +1,18 @@
|
|||||||
|
import { IAdapter, RepositoryBuilder } from "@/contexts/common/domain";
|
||||||
|
import { Email } from "@shared/contexts";
|
||||||
|
import { User } from "../domain";
|
||||||
|
import { IAuthRepository } from "../domain/repository";
|
||||||
|
|
||||||
|
export const findUserByEmail = async (
|
||||||
|
email: Email,
|
||||||
|
adapter: IAdapter,
|
||||||
|
repository: RepositoryBuilder<IAuthRepository>,
|
||||||
|
): Promise<User | null> => {
|
||||||
|
const user = await adapter
|
||||||
|
.startTransaction()
|
||||||
|
.complete(async (t) =>
|
||||||
|
repository({ transaction: t }).findUserByEmail(email),
|
||||||
|
);
|
||||||
|
|
||||||
|
return user;
|
||||||
|
};
|
||||||
@ -1 +1,2 @@
|
|||||||
export * from "./authServices";
|
export * from "./FindUserByEmail.useCase";
|
||||||
|
export * from "./Login.useCase";
|
||||||
|
|||||||
@ -4,11 +4,13 @@ import {
|
|||||||
AggregateRoot,
|
AggregateRoot,
|
||||||
Email,
|
Email,
|
||||||
IDomainError,
|
IDomainError,
|
||||||
|
Name,
|
||||||
Result,
|
Result,
|
||||||
UniqueID,
|
UniqueID,
|
||||||
} from "@shared/contexts";
|
} from "@shared/contexts";
|
||||||
|
|
||||||
export interface IUserProps {
|
export interface IUserProps {
|
||||||
|
name: Name;
|
||||||
email: Email;
|
email: Email;
|
||||||
password?: string;
|
password?: string;
|
||||||
hashed_password?: string;
|
hashed_password?: string;
|
||||||
@ -16,6 +18,7 @@ export interface IUserProps {
|
|||||||
|
|
||||||
export interface IUser {
|
export interface IUser {
|
||||||
id: UniqueID;
|
id: UniqueID;
|
||||||
|
name: Name;
|
||||||
email: Email;
|
email: Email;
|
||||||
hashed_password: string;
|
hashed_password: string;
|
||||||
|
|
||||||
@ -51,6 +54,10 @@ export class User extends AggregateRoot<IUserProps> implements IUser {
|
|||||||
this._protectPassword(props);
|
this._protectPassword(props);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get name(): Name {
|
||||||
|
return this.props.name;
|
||||||
|
}
|
||||||
|
|
||||||
get email(): Email {
|
get email(): Email {
|
||||||
return this.props.email;
|
return this.props.email;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,8 +1,7 @@
|
|||||||
import { IRepository } from "@/contexts/common/domain";
|
import { IRepository } from "@/contexts/common/domain";
|
||||||
import { Email, UniqueID } from "@shared/contexts";
|
import { Email } from "@shared/contexts";
|
||||||
import { User } from "../entities";
|
import { User } from "../entities";
|
||||||
|
|
||||||
export interface IAuthRepository extends IRepository<any> {
|
export interface IAuthRepository extends IRepository<any> {
|
||||||
getById(id: UniqueID): Promise<User | null>;
|
findUserByEmail(email: Email): Promise<User | null>;
|
||||||
findByEmail(email: Email): Promise<User | null>;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -41,7 +41,7 @@ export class AuthRepository
|
|||||||
return this.mapper.mapToDomain(rawUser);
|
return this.mapper.mapToDomain(rawUser);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async findByEmail(email: Email): Promise<User | null> {
|
public async findUserByEmail(email: Email): Promise<User | null> {
|
||||||
const rawUser: any = await this._getBy(
|
const rawUser: any = await this._getBy(
|
||||||
"User_Model",
|
"User_Model",
|
||||||
"email",
|
"email",
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
// Import the necessary packages and modules
|
// Import the necessary packages and modules
|
||||||
|
import { User } from "@/contexts/auth/domain";
|
||||||
import { IServerError } from "@/contexts/common/domain/errors";
|
import { IServerError } from "@/contexts/common/domain/errors";
|
||||||
import { ExpressController } from "@/contexts/common/infrastructure/express";
|
import { ExpressController } from "@/contexts/common/infrastructure/express";
|
||||||
import passport from "passport";
|
import passport from "passport";
|
||||||
@ -41,7 +42,7 @@ export class AuthenticateController extends ExpressController {
|
|||||||
{ session: false },
|
{ session: false },
|
||||||
(
|
(
|
||||||
err: any,
|
err: any,
|
||||||
user?: Express.User | false | null,
|
user?: User | false | null,
|
||||||
info?: object | string | Array<string | undefined>,
|
info?: object | string | Array<string | undefined>,
|
||||||
status?: number | Array<number | undefined>,
|
status?: number | Array<number | undefined>,
|
||||||
) => {
|
) => {
|
||||||
|
|||||||
@ -1,108 +0,0 @@
|
|||||||
import { IUseCaseError, UseCaseError } from "@/contexts/common/application";
|
|
||||||
import { IServerError } from "@/contexts/common/domain/errors";
|
|
||||||
import {
|
|
||||||
IInfrastructureError,
|
|
||||||
InfrastructureError,
|
|
||||||
handleInfrastructureError,
|
|
||||||
} from "@/contexts/common/infrastructure";
|
|
||||||
import { ExpressController } from "@/contexts/common/infrastructure/express";
|
|
||||||
import { ILogin_DTO, ensureLogin_DTOIsValid } from "@shared/contexts";
|
|
||||||
|
|
||||||
export class LoginController extends ExpressController {
|
|
||||||
private useCase: LoginUseCase;
|
|
||||||
private presenter: ILoginPresenter;
|
|
||||||
private context: IAuthContext;
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
props: {
|
|
||||||
useCase: LoginUseCase;
|
|
||||||
presenter: ILoginPresenter;
|
|
||||||
},
|
|
||||||
context: IAuthContext,
|
|
||||||
) {
|
|
||||||
super();
|
|
||||||
|
|
||||||
const { useCase, presenter } = props;
|
|
||||||
this.useCase = useCase;
|
|
||||||
this.presenter = presenter;
|
|
||||||
this.context = context;
|
|
||||||
}
|
|
||||||
|
|
||||||
async executeImpl() {
|
|
||||||
try {
|
|
||||||
const loginDTO: ILogin_DTO = this.req.body;
|
|
||||||
|
|
||||||
// Validaciones de DTO
|
|
||||||
const loginDTOOrError = ensureLogin_DTOIsValid(loginDTO);
|
|
||||||
|
|
||||||
if (loginDTOOrError.isFailure) {
|
|
||||||
const errorMessage = "Login data not valid";
|
|
||||||
const infraError = handleInfrastructureError(
|
|
||||||
InfrastructureError.INVALID_INPUT_DATA,
|
|
||||||
errorMessage,
|
|
||||||
loginDTOOrError.error,
|
|
||||||
);
|
|
||||||
return this.invalidInputError(errorMessage, infraError);
|
|
||||||
}
|
|
||||||
|
|
||||||
const result = await this.useCase.execute();
|
|
||||||
|
|
||||||
if (result.isFailure) {
|
|
||||||
return this._handleExecuteError(result.error);
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log("login OK => generate token JWT");
|
|
||||||
|
|
||||||
const customer = <Customer>result.object;
|
|
||||||
|
|
||||||
return this.created<ICreateCustomer_Response_DTO>(
|
|
||||||
this.presenter.map(customer, this.context),
|
|
||||||
);
|
|
||||||
} catch (e: unknown) {
|
|
||||||
return this.fail(e as IServerError);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private _handleExecuteError(error: IUseCaseError) {
|
|
||||||
let errorMessage: string;
|
|
||||||
let infraError: IInfrastructureError;
|
|
||||||
|
|
||||||
switch (error.code) {
|
|
||||||
case UseCaseError.INVALID_INPUT_DATA:
|
|
||||||
errorMessage = "Login data not valid";
|
|
||||||
infraError = handleInfrastructureError(
|
|
||||||
InfrastructureError.INVALID_INPUT_DATA,
|
|
||||||
errorMessage,
|
|
||||||
error,
|
|
||||||
);
|
|
||||||
return this.invalidInputError(errorMessage, infraError);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case UseCaseError.NOT_FOUND_ERROR:
|
|
||||||
errorMessage = "User not found";
|
|
||||||
|
|
||||||
infraError = handleInfrastructureError(
|
|
||||||
InfrastructureError.INVALID_INPUT_DATA,
|
|
||||||
errorMessage,
|
|
||||||
error,
|
|
||||||
);
|
|
||||||
return this.conflictError(error.message, error);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case UseCaseError.UNEXCEPTED_ERROR:
|
|
||||||
errorMessage = error.message;
|
|
||||||
|
|
||||||
infraError = handleInfrastructureError(
|
|
||||||
InfrastructureError.UNEXCEPTED_ERROR,
|
|
||||||
errorMessage,
|
|
||||||
error,
|
|
||||||
);
|
|
||||||
return this.internalServerError(errorMessage, infraError);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
errorMessage = error.message;
|
|
||||||
return this.clientError(errorMessage);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,20 +1 @@
|
|||||||
import { AuthenticateController } from "./AuthenticateController";
|
export * from "./login";
|
||||||
|
|
||||||
const authenticate = (context: any) => {
|
|
||||||
//const adapter = context.adapter;
|
|
||||||
//const repoManager = context.repositoryManager;
|
|
||||||
|
|
||||||
/*repoManager.registerRepository("Auth", (params = { transaction: null }) => {
|
|
||||||
const { transaction } = params;
|
|
||||||
|
|
||||||
return new AuthRepository({
|
|
||||||
transaction,
|
|
||||||
adapter,
|
|
||||||
mapper: createAuthMapper(context),
|
|
||||||
});
|
|
||||||
});*/
|
|
||||||
|
|
||||||
//const listArticlesUseCase = new ListArticlesUseCase(context);
|
|
||||||
|
|
||||||
return new AuthenticateController();
|
|
||||||
};
|
|
||||||
|
|||||||
@ -0,0 +1,71 @@
|
|||||||
|
import { config } from "@/config";
|
||||||
|
import { User } from "@/contexts/auth/domain";
|
||||||
|
import { IServerError } from "@/contexts/common/domain/errors";
|
||||||
|
import {
|
||||||
|
InfrastructureError,
|
||||||
|
handleInfrastructureError,
|
||||||
|
} from "@/contexts/common/infrastructure";
|
||||||
|
import { ExpressController } from "@/contexts/common/infrastructure/express";
|
||||||
|
import { ILogin_Response_DTO } from "@shared/contexts";
|
||||||
|
import JWT from "jsonwebtoken";
|
||||||
|
import { IAuthContext } from "../../../Auth.context";
|
||||||
|
import { ILoginPresenter, ILoginUser } from "./presenter";
|
||||||
|
|
||||||
|
export class LoginController extends ExpressController {
|
||||||
|
private presenter: ILoginPresenter;
|
||||||
|
private context: IAuthContext;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
props: {
|
||||||
|
presenter: ILoginPresenter;
|
||||||
|
},
|
||||||
|
context: IAuthContext,
|
||||||
|
) {
|
||||||
|
super();
|
||||||
|
|
||||||
|
const { presenter } = props;
|
||||||
|
this.presenter = presenter;
|
||||||
|
this.context = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
async executeImpl() {
|
||||||
|
try {
|
||||||
|
const user = <User>this.req.user;
|
||||||
|
|
||||||
|
if (!user) {
|
||||||
|
const errorMessage = "Unexpected missing user data";
|
||||||
|
const infraError = handleInfrastructureError(
|
||||||
|
InfrastructureError.UNEXCEPTED_ERROR,
|
||||||
|
errorMessage,
|
||||||
|
);
|
||||||
|
return this.internalServerError(errorMessage, infraError);
|
||||||
|
}
|
||||||
|
|
||||||
|
const loginUser: ILoginUser = {
|
||||||
|
user,
|
||||||
|
token: this._generateUserToken(user),
|
||||||
|
refreshToken: this._generateUserRefreshToken(user),
|
||||||
|
};
|
||||||
|
|
||||||
|
return this.ok<ILogin_Response_DTO>(
|
||||||
|
this.presenter.map(loginUser, this.context),
|
||||||
|
);
|
||||||
|
} catch (e: unknown) {
|
||||||
|
return this.fail(e as IServerError);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private _generateUserToken(user: User) {
|
||||||
|
return JWT.sign({ email: user.email.toString() }, config.jwt.secret_key, {
|
||||||
|
expiresIn: config.jwt.token_expiration,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private _generateUserRefreshToken(user: User) {
|
||||||
|
return JWT.sign(
|
||||||
|
{ email: user.email.toString() },
|
||||||
|
config.jwt.refresh_secret_key,
|
||||||
|
{ expiresIn: config.jwt.refresh_token_expiration },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,13 @@
|
|||||||
|
import { IAuthContext } from "../../../Auth.context";
|
||||||
|
import { LoginController } from "./Login.controller";
|
||||||
|
import { loginPresenter } from "./presenter";
|
||||||
|
|
||||||
|
export const createLoginController = (context: IAuthContext) => {
|
||||||
|
return new LoginController(
|
||||||
|
{
|
||||||
|
//useCase: listArticlesUseCase,
|
||||||
|
presenter: loginPresenter,
|
||||||
|
},
|
||||||
|
context,
|
||||||
|
);
|
||||||
|
};
|
||||||
@ -0,0 +1,29 @@
|
|||||||
|
import { IUser } from "@/contexts/auth/domain";
|
||||||
|
import { IAuthContext } from "@/contexts/auth/infrastructure/Auth.context";
|
||||||
|
import { ILogin_Response_DTO } from "@shared/contexts";
|
||||||
|
|
||||||
|
export interface ILoginUser {
|
||||||
|
user: IUser;
|
||||||
|
token: string;
|
||||||
|
refreshToken: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ILoginPresenter {
|
||||||
|
map: (user: ILoginUser, context: IAuthContext) => ILogin_Response_DTO;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const loginPresenter: ILoginPresenter = {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
|
map: (loginUser: ILoginUser, context: IAuthContext): ILogin_Response_DTO => {
|
||||||
|
const { user, token, refreshToken } = loginUser;
|
||||||
|
|
||||||
|
return {
|
||||||
|
id: user.id.toString(),
|
||||||
|
name: user.name.toString(),
|
||||||
|
email: user.email.toString(),
|
||||||
|
roles: ["ROLE_USER"],
|
||||||
|
token,
|
||||||
|
refresh_token: refreshToken,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
@ -0,0 +1 @@
|
|||||||
|
export * from "./Login.presenter";
|
||||||
@ -1,9 +1,12 @@
|
|||||||
/* eslint-disable @typescript-eslint/no-unused-vars */
|
/* eslint-disable @typescript-eslint/no-unused-vars */
|
||||||
|
|
||||||
import Express from "express";
|
|
||||||
import passport from "passport";
|
import passport from "passport";
|
||||||
|
|
||||||
export const authenticate = (
|
export const isLoggedUser = passport.authenticate("local-jwt", {
|
||||||
|
session: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
/*export const authenticate = (
|
||||||
req: Express.Request,
|
req: Express.Request,
|
||||||
res: Express.Response,
|
res: Express.Response,
|
||||||
next: Express.NextFunction,
|
next: Express.NextFunction,
|
||||||
@ -14,7 +17,7 @@ export const authenticate = (
|
|||||||
{ session: false },
|
{ session: false },
|
||||||
(
|
(
|
||||||
err: any,
|
err: any,
|
||||||
user?: Express.User | false | null,
|
user?: User | false | null,
|
||||||
info?: object | string | Array<string | undefined>,
|
info?: object | string | Array<string | undefined>,
|
||||||
status?: number | Array<number | undefined>,
|
status?: number | Array<number | undefined>,
|
||||||
) => {
|
) => {
|
||||||
@ -32,3 +35,6 @@ export const authenticate = (
|
|||||||
},
|
},
|
||||||
)(req, res, next);
|
)(req, res, next);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
*/
|
||||||
@ -1,11 +1,10 @@
|
|||||||
import { PassportStatic } from "passport";
|
import { PassportStatic } from "passport";
|
||||||
import { AuthContext } from "../../Auth.context";
|
import { AuthContext } from "../../Auth.context";
|
||||||
import { initEmailStrategy } from "./emailStrategy";
|
import { initEmailStrategy } from "./emailStrategy";
|
||||||
import { jwtStrategy } from "./jwtStrategy";
|
import { initJWTStrategy } from "./jwtStrategy";
|
||||||
|
|
||||||
// Export a function that will be used to configure Passport authentication
|
// Export a function that will be used to configure Passport authentication
|
||||||
export const configurePassportAuth = (passport: PassportStatic) => {
|
export const configurePassportAuth = (passport: PassportStatic) => {
|
||||||
console.log("passport: configuring strategies !!!!!!!!!!!!!!!!!!");
|
|
||||||
passport.use("local-email", initEmailStrategy(AuthContext.getInstance()));
|
passport.use("local-email", initEmailStrategy(AuthContext.getInstance()));
|
||||||
passport.use("local-jwt", jwtStrategy);
|
passport.use("local-jwt", initJWTStrategy(AuthContext.getInstance()));
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,9 +1,10 @@
|
|||||||
import { LoginUseCase } from "@/contexts/auth/application/LoginUseCase";
|
|
||||||
import { IServerError } from "@/contexts/common/domain/errors";
|
import { IServerError } from "@/contexts/common/domain/errors";
|
||||||
import { PassportStrategyController } from "@/contexts/common/infrastructure/express";
|
import { PassportStrategyController } from "@/contexts/common/infrastructure/express";
|
||||||
import { ensureLogin_DTOIsValid } from "@shared/contexts";
|
import { ensureLogin_DTOIsValid } from "@shared/contexts";
|
||||||
import { Strategy as EmailStrategy, IVerifyOptions } from "passport-local";
|
import { Strategy as EmailStrategy, IVerifyOptions } from "passport-local";
|
||||||
|
|
||||||
|
import { LoginUseCase } from "@/contexts/auth/application";
|
||||||
|
import { User } from "@/contexts/auth/domain";
|
||||||
import { IAuthContext } from "../../Auth.context";
|
import { IAuthContext } from "../../Auth.context";
|
||||||
import { registerAuthRepository } from "../../Auth.repository";
|
import { registerAuthRepository } from "../../Auth.repository";
|
||||||
|
|
||||||
@ -32,11 +33,7 @@ class EmailStrategyController extends PassportStrategyController {
|
|||||||
public async verifyStrategy(
|
public async verifyStrategy(
|
||||||
email: string,
|
email: string,
|
||||||
password: string,
|
password: string,
|
||||||
done: (
|
done: (error: any, user?: User | false, options?: IVerifyOptions) => void,
|
||||||
error: any,
|
|
||||||
user?: Express.User | false,
|
|
||||||
options?: IVerifyOptions,
|
|
||||||
) => void,
|
|
||||||
) {
|
) {
|
||||||
const loginDTOOrError = ensureLogin_DTOIsValid({ email, password });
|
const loginDTOOrError = ensureLogin_DTOIsValid({ email, password });
|
||||||
|
|
||||||
|
|||||||
@ -1,2 +1,2 @@
|
|||||||
export * from "./authenticate";
|
export * from "./authMiddleware";
|
||||||
export * from "./configurePassportAuth";
|
export * from "./configurePassportAuth";
|
||||||
|
|||||||
@ -1,27 +1,60 @@
|
|||||||
import { config } from "@/config";
|
import { config } from "@/config";
|
||||||
import { ExtractJwt, Strategy as JWTStrategy } from "passport-jwt";
|
import { FindUserByEmailUseCase } from "@/contexts/auth/application/FindUserByEmail.useCase";
|
||||||
|
import { IServerError } from "@/contexts/common/domain/errors";
|
||||||
|
import { PassportStrategyController } from "@/contexts/common/infrastructure/express";
|
||||||
|
import {
|
||||||
|
ExtractJwt,
|
||||||
|
Strategy as JWTStrategy,
|
||||||
|
VerifiedCallback,
|
||||||
|
} from "passport-jwt";
|
||||||
|
import { IAuthContext } from "../../Auth.context";
|
||||||
|
import { registerAuthRepository } from "../../Auth.repository";
|
||||||
|
|
||||||
const strategyOpts = {
|
const strategyOpts = {
|
||||||
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(), // Extract the JWT from the Authorization header
|
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(), // Extract the JWT from the Authorization header
|
||||||
secretOrKey: config.jwt.secret_key,
|
secretOrKey: config.jwt.secret_key,
|
||||||
};
|
};
|
||||||
|
|
||||||
export const jwtStrategy = new JWTStrategy(
|
class JWTStrategyController extends PassportStrategyController {
|
||||||
strategyOpts,
|
private useCase: FindUserByEmailUseCase;
|
||||||
async (jwt_payload, done) => {
|
private context: IAuthContext;
|
||||||
console.log(
|
|
||||||
"PASSPORT USE LOCAL-JWT !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
|
|
||||||
);
|
|
||||||
console.log(jwt_payload);
|
|
||||||
|
|
||||||
/*
|
constructor(
|
||||||
const user = await authenticateUserByEmail("assa@asds.com", "password");
|
props: {
|
||||||
if (user) {
|
useCase: FindUserByEmailUseCase;
|
||||||
return done(null, user);
|
},
|
||||||
} else {
|
context: any,
|
||||||
return done(null, false);
|
) {
|
||||||
|
super();
|
||||||
|
|
||||||
|
const { useCase } = props;
|
||||||
|
this.useCase = useCase;
|
||||||
|
this.context = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async verifyStrategy(payload: any, done: VerifiedCallback) {
|
||||||
|
const { email } = payload;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const result = await this.useCase.execute({ email });
|
||||||
|
if (result.isFailure) {
|
||||||
|
return done(null, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
return done(null, result.object);
|
||||||
|
} catch (e: unknown) {
|
||||||
|
return done(e as IServerError);
|
||||||
}
|
}
|
||||||
*/
|
}
|
||||||
return done(null, { id: "xzxxxxx", email: "assa@asds.com" });
|
}
|
||||||
},
|
|
||||||
);
|
export const initJWTStrategy = (context: IAuthContext) =>
|
||||||
|
new JWTStrategy(strategyOpts, async (...params) => {
|
||||||
|
registerAuthRepository(context);
|
||||||
|
return new JWTStrategyController(
|
||||||
|
{
|
||||||
|
useCase: new FindUserByEmailUseCase(context),
|
||||||
|
},
|
||||||
|
context,
|
||||||
|
).verifyStrategy(...params);
|
||||||
|
});
|
||||||
|
|||||||
@ -1,184 +0,0 @@
|
|||||||
import {
|
|
||||||
InfrastructureError,
|
|
||||||
handleInfrastructureError,
|
|
||||||
} from "@/contexts/common/infrastructure";
|
|
||||||
import { ensureLogin_DTOIsValid } from "@shared/contexts";
|
|
||||||
import passport from "passport";
|
|
||||||
import { ExtractJwt, Strategy as JwtStrategy } from "passport-jwt";
|
|
||||||
import { Strategy as LocalStrategy } from "passport-local";
|
|
||||||
|
|
||||||
/*declare global {
|
|
||||||
namespace Express {
|
|
||||||
interface User {
|
|
||||||
id?: string;
|
|
||||||
email: string;
|
|
||||||
password: string;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
|
|
||||||
//import { authenticateUserByEmail, deserializeUserById } from './../../../services';
|
|
||||||
const authenticateUserByEmail = async (
|
|
||||||
email: string,
|
|
||||||
password: string,
|
|
||||||
): Promise<Express.User | Error> => {
|
|
||||||
// Simulación de búsqueda del usuario en la base de datos
|
|
||||||
const user = {
|
|
||||||
id: "1",
|
|
||||||
email: "usuario@example.com",
|
|
||||||
password: "$2a$10$EdfkgQ7vMTGvXq1qI7qJQ.g3WiYGqCSCdzhZ/LG20YKwA1YjgLJnO",
|
|
||||||
}; // Contraseña hasheada: "password"
|
|
||||||
|
|
||||||
return user;
|
|
||||||
|
|
||||||
/*const res = await pool.query('SELECT * FROM users WHERE email = $1', [email]);
|
|
||||||
|
|
||||||
if (res.rows.length) {
|
|
||||||
const user = res.rows[0];
|
|
||||||
const match = await bcrypt.compare(password, user.password);
|
|
||||||
|
|
||||||
if (match) {
|
|
||||||
return user;
|
|
||||||
} else {
|
|
||||||
throw new Error('Incorrect email and/or password');
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
throw new Error('User not found');
|
|
||||||
}*/
|
|
||||||
};
|
|
||||||
|
|
||||||
const deserializeUserById = async (
|
|
||||||
id: number,
|
|
||||||
): Promise<Express.User | Error> => {
|
|
||||||
/*const res = await pool.query('SELECT * FROM users WHERE id = $1', [id]);
|
|
||||||
|
|
||||||
if (res.rows.length) {
|
|
||||||
return res.rows[0];
|
|
||||||
} else {
|
|
||||||
throw new Error('User was not found');
|
|
||||||
}*/
|
|
||||||
|
|
||||||
const user = {
|
|
||||||
id: "1",
|
|
||||||
email: "usuario@example.com",
|
|
||||||
password: "$2a$10$EdfkgQ7vMTGvXq1qI7qJQ.g3WiYGqCSCdzhZ/LG20YKwA1YjgLJnO",
|
|
||||||
}; // Contraseña hasheada: "password"
|
|
||||||
|
|
||||||
return user;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Configurar la estrategia de autenticación local de Passport.js
|
|
||||||
passport.use(
|
|
||||||
"local-email",
|
|
||||||
new LocalStrategy(
|
|
||||||
{
|
|
||||||
usernameField: "email", // Campo utilizado para el email en el formulario
|
|
||||||
passwordField: "password",
|
|
||||||
},
|
|
||||||
async (email, password, done) => {
|
|
||||||
console.log("local-email");
|
|
||||||
|
|
||||||
const loginDTO = { email, password };
|
|
||||||
const loginDTOOrError = ensureLogin_DTOIsValid(loginDTO);
|
|
||||||
|
|
||||||
if (loginDTOOrError.isFailure) {
|
|
||||||
const errorMessage = "Login data not valid";
|
|
||||||
const infraError = handleInfrastructureError(
|
|
||||||
InfrastructureError.INVALID_INPUT_DATA,
|
|
||||||
errorMessage,
|
|
||||||
loginDTOOrError.error,
|
|
||||||
);
|
|
||||||
done(infraError);
|
|
||||||
}
|
|
||||||
|
|
||||||
const result = await this.useCase.execute();
|
|
||||||
|
|
||||||
try {
|
|
||||||
// Buscar el usuario en la base de datos por email
|
|
||||||
const user = await authenticateUserByEmail(email, password);
|
|
||||||
return done(null, user as Express.User);
|
|
||||||
} catch (error) {
|
|
||||||
return done(error);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
passport.use(
|
|
||||||
"local-jwt",
|
|
||||||
new JwtStrategy(
|
|
||||||
{
|
|
||||||
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
|
|
||||||
secretOrKey: "secret",
|
|
||||||
},
|
|
||||||
async (jwt_payload, done) => {
|
|
||||||
console.log(jwt_payload);
|
|
||||||
|
|
||||||
const user = await authenticateUserByEmail("assa@asds.com", "password");
|
|
||||||
return done(null, user);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
/*passport.use(
|
|
||||||
"jwt2",
|
|
||||||
new CustomStrategy(async (req, done) => {
|
|
||||||
const token =
|
|
||||||
req && req.headers && req.headers["x-access-token"]
|
|
||||||
? req.headers["x-access-token"]
|
|
||||||
: null;
|
|
||||||
const appVersion =
|
|
||||||
req && req.headers && req.headers["accept-version"]
|
|
||||||
? req.headers["accept-version"]
|
|
||||||
: null;
|
|
||||||
console.log("appVersion: ", appVersion);
|
|
||||||
|
|
||||||
if (!token) {
|
|
||||||
console.error("Unauthorized. Token missing.");
|
|
||||||
return done(null, false, { message: "Unauthorized. Token missing." });
|
|
||||||
}
|
|
||||||
|
|
||||||
const result = securityHelper.verify(token);
|
|
||||||
//console.log('token result => ', result);
|
|
||||||
|
|
||||||
if (result && result.id) {
|
|
||||||
//recuperamos el usuario de la petición
|
|
||||||
let user = await authService.extraMethods.findUser({ id: result.id });
|
|
||||||
if (user) {
|
|
||||||
user = user.toJSON();
|
|
||||||
userService._updateLastLoginAndVersionUser(user.id, appVersion);
|
|
||||||
user.app_version = appVersion;
|
|
||||||
user.token = token;
|
|
||||||
delete user.password;
|
|
||||||
|
|
||||||
console.log("Logged in Successfully");
|
|
||||||
console.log(user);
|
|
||||||
return done(null, user, { message: "Logged in Successfully" });
|
|
||||||
} else {
|
|
||||||
console.error("Unauthorized. User not found.");
|
|
||||||
return done(null, false, { message: "Unauthorized. User not found." });
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
//console.log('Token no válido');
|
|
||||||
console.error("Unauthorized. Invalid token.");
|
|
||||||
return done(null, false, { message: "Unauthorized. Invalid token." });
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
);*/
|
|
||||||
|
|
||||||
// Serializar y deserializar el usuario para almacenar y recuperar la sesión
|
|
||||||
passport.serializeUser((user: Express.User, done) => {
|
|
||||||
done(null, user.id);
|
|
||||||
});
|
|
||||||
|
|
||||||
passport.deserializeUser(async (id: number, done) => {
|
|
||||||
try {
|
|
||||||
const user = await deserializeUserById(id);
|
|
||||||
|
|
||||||
done(null, user as Express.User);
|
|
||||||
} catch (error) {
|
|
||||||
done(error, null);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
export { passport };
|
|
||||||
@ -1,8 +1,8 @@
|
|||||||
import { config } from "@/config";
|
import { registerMiddleware } from "@/contexts/common/infrastructure/express";
|
||||||
import Express from "express";
|
import Express from "express";
|
||||||
import JWT from "jsonwebtoken";
|
|
||||||
import passport from "passport";
|
import passport from "passport";
|
||||||
import { User } from "../../domain";
|
import { createLoginController } from "./controllers";
|
||||||
|
import { isLoggedUser } from "./passport";
|
||||||
|
|
||||||
/*authRoutes.post(
|
/*authRoutes.post(
|
||||||
"/login",
|
"/login",
|
||||||
@ -40,48 +40,13 @@ authRoutes.get(
|
|||||||
export const AuthRouter = (appRouter: Express.Router) => {
|
export const AuthRouter = (appRouter: Express.Router) => {
|
||||||
const authRoutes: Express.Router = Express.Router({ mergeParams: true });
|
const authRoutes: Express.Router = Express.Router({ mergeParams: true });
|
||||||
|
|
||||||
//appRouter.use(registerMiddleware("authenticate", authenticate));
|
appRouter.use(registerMiddleware("isLoggedUser", isLoggedUser));
|
||||||
|
|
||||||
authRoutes.post(
|
authRoutes.post(
|
||||||
"/login",
|
"/login",
|
||||||
passport.authenticate("local-email", { session: false }),
|
passport.authenticate("local-email", { session: false }),
|
||||||
(req, res, next) => {
|
|
||||||
if (req.isAuthenticated()) {
|
|
||||||
const user: User = req.user;
|
|
||||||
|
|
||||||
const accessToken = JWT.sign(
|
|
||||||
{ id: user.id, email: user.email },
|
|
||||||
config.jwt.secret_key,
|
|
||||||
{ expiresIn: config.jwt.token_expiration },
|
|
||||||
);
|
|
||||||
const refreshToken = JWT.sign(
|
|
||||||
{ id: user.id, email: user.email },
|
|
||||||
config.jwt.refresh_secret_key,
|
|
||||||
{ expiresIn: config.jwt.refresh_token_expiration },
|
|
||||||
);
|
|
||||||
|
|
||||||
//refreshTokens.push(refreshToken);
|
|
||||||
|
|
||||||
return res.json({ accessToken, refreshToken });
|
|
||||||
}
|
|
||||||
return res.status(401).json({});
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
authRoutes.post(
|
|
||||||
"/login2",
|
|
||||||
(req: Express.Request, res: Express.Response, next: Express.NextFunction) =>
|
(req: Express.Request, res: Express.Response, next: Express.NextFunction) =>
|
||||||
passport.authenticate(
|
createLoginController(res.locals["context"]).execute(req, res, next),
|
||||||
"local-email",
|
|
||||||
{ session: false },
|
|
||||||
(err, user, info) => {
|
|
||||||
console.log(err, user, info);
|
|
||||||
next(err);
|
|
||||||
},
|
|
||||||
)(req, res, next),
|
|
||||||
(req, res, next) => {
|
|
||||||
res.status(200).json({});
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
|
|
||||||
appRouter.use("/auth", authRoutes);
|
appRouter.use("/auth", authRoutes);
|
||||||
|
|||||||
@ -2,7 +2,7 @@ import {
|
|||||||
ISequelizeMapper,
|
ISequelizeMapper,
|
||||||
SequelizeMapper,
|
SequelizeMapper,
|
||||||
} from "@/contexts/common/infrastructure";
|
} from "@/contexts/common/infrastructure";
|
||||||
import { Email, UniqueID } from "@shared/contexts";
|
import { Email, Name, UniqueID } from "@shared/contexts";
|
||||||
import { IUserProps, User } from "../../domain/entities";
|
import { IUserProps, User } from "../../domain/entities";
|
||||||
import { IAuthContext } from "../Auth.context";
|
import { IAuthContext } from "../Auth.context";
|
||||||
import { TCreationUser_Attributes, User_Model } from "../sequelize/user.model";
|
import { TCreationUser_Attributes, User_Model } from "../sequelize/user.model";
|
||||||
@ -20,6 +20,7 @@ class UserMapper
|
|||||||
|
|
||||||
protected toDomainMappingImpl(source: User_Model, params: any): User {
|
protected toDomainMappingImpl(source: User_Model, params: any): User {
|
||||||
const props: IUserProps = {
|
const props: IUserProps = {
|
||||||
|
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: source.password,
|
||||||
};
|
};
|
||||||
@ -40,6 +41,7 @@ class UserMapper
|
|||||||
) {
|
) {
|
||||||
return {
|
return {
|
||||||
id: source.id.toPrimitive(),
|
id: source.id.toPrimitive(),
|
||||||
|
name: source.name.toPrimitive(),
|
||||||
email: source.email.toPrimitive(),
|
email: source.email.toPrimitive(),
|
||||||
password: source.hashed_password,
|
password: source.hashed_password,
|
||||||
};
|
};
|
||||||
|
|||||||
@ -20,6 +20,7 @@ export class User_Model extends Model<
|
|||||||
static associate(connection: Sequelize) {}
|
static associate(connection: Sequelize) {}
|
||||||
|
|
||||||
declare id: string;
|
declare id: string;
|
||||||
|
declare name: string;
|
||||||
declare email: string;
|
declare email: string;
|
||||||
declare password: string;
|
declare password: string;
|
||||||
}
|
}
|
||||||
@ -32,10 +33,15 @@ export default (sequelize: Sequelize) => {
|
|||||||
primaryKey: true,
|
primaryKey: true,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
name: {
|
||||||
|
type: DataTypes.STRING,
|
||||||
|
},
|
||||||
|
|
||||||
email: {
|
email: {
|
||||||
type: DataTypes.STRING,
|
type: DataTypes.STRING,
|
||||||
allowNull: false,
|
allowNull: false,
|
||||||
},
|
},
|
||||||
|
|
||||||
password: {
|
password: {
|
||||||
type: DataTypes.STRING,
|
type: DataTypes.STRING,
|
||||||
allowNull: false,
|
allowNull: false,
|
||||||
@ -45,15 +51,15 @@ export default (sequelize: Sequelize) => {
|
|||||||
sequelize,
|
sequelize,
|
||||||
tableName: "users",
|
tableName: "users",
|
||||||
|
|
||||||
//paranoid: true, // softs deletes
|
paranoid: true, // softs deletes
|
||||||
//timestamps: true,
|
timestamps: true,
|
||||||
//version: true,
|
//version: true,
|
||||||
|
|
||||||
//createdAt: "created_at",
|
createdAt: "created_at",
|
||||||
//updatedAt: "updated_at",
|
updatedAt: "updated_at",
|
||||||
//deletedAt: "deleted_at",
|
deletedAt: "deleted_at",
|
||||||
|
|
||||||
indexes: [{ name: "email_idx", unique: true, fields: ["email"] }],
|
indexes: [{ name: "email_idx", fields: ["email"] }],
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@ -13,7 +13,7 @@ export const CatalogRouter = (appRouter: Express.Router) => {
|
|||||||
|
|
||||||
catalogRoutes.get(
|
catalogRoutes.get(
|
||||||
"/",
|
"/",
|
||||||
applyMiddleware("authenticate"),
|
applyMiddleware("isLoggedUser"),
|
||||||
(req: Express.Request, res: Express.Response, next: Express.NextFunction) =>
|
(req: Express.Request, res: Express.Response, next: Express.NextFunction) =>
|
||||||
createListArticlesController(res.locals["context"]).execute(
|
createListArticlesController(res.locals["context"]).execute(
|
||||||
req,
|
req,
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { TBusinessTransaction } from "./BusinessTransaction.interface";
|
import { TBusinessTransaction } from "./BusinessTransaction";
|
||||||
|
|
||||||
export interface IAdapter {
|
export interface IAdapter {
|
||||||
startTransaction: () => TBusinessTransaction;
|
startTransaction: () => TBusinessTransaction;
|
||||||
|
|||||||
@ -1,5 +0,0 @@
|
|||||||
type TUnitOfWork = {
|
|
||||||
start(): unknown;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type TBusinessTransaction = TUnitOfWork;
|
|
||||||
@ -0,0 +1,4 @@
|
|||||||
|
export type TBusinessTransaction = {
|
||||||
|
start(): void;
|
||||||
|
complete<T>(work: (...params: any[]) => Promise<T>): Promise<T>;
|
||||||
|
};
|
||||||
@ -1,5 +1,5 @@
|
|||||||
export * from "./Adapter.interface";
|
export * from "./Adapter.interface";
|
||||||
export * from "./BusinessTransaction.interface";
|
export * from "./BusinessTransaction";
|
||||||
export * from "./Repository.interface";
|
export * from "./Repository.interface";
|
||||||
export * from "./RepositoryBuilder";
|
export * from "./RepositoryBuilder";
|
||||||
export * from "./RepositoryManager";
|
export * from "./RepositoryManager";
|
||||||
|
|||||||
@ -18,7 +18,7 @@ export class InfrastructureError
|
|||||||
public static create(
|
public static create(
|
||||||
code: string,
|
code: string,
|
||||||
message: string,
|
message: string,
|
||||||
payload?: Record<string, any>
|
payload?: Record<string, any>,
|
||||||
): InfrastructureError {
|
): InfrastructureError {
|
||||||
return new InfrastructureError(code, message, payload);
|
return new InfrastructureError(code, message, payload);
|
||||||
}
|
}
|
||||||
@ -31,16 +31,17 @@ function _isJoiError(error: Error) {
|
|||||||
export function handleInfrastructureError(
|
export function handleInfrastructureError(
|
||||||
code: string,
|
code: string,
|
||||||
message: string,
|
message: string,
|
||||||
error: Error // UseCaseError | ValidationError
|
error?: Error, // UseCaseError | ValidationError
|
||||||
): IInfrastructureError {
|
): IInfrastructureError {
|
||||||
let payload = {};
|
let payload = {};
|
||||||
|
|
||||||
if (_isJoiError(error)) {
|
if (error) {
|
||||||
//Joi => error.details
|
if (_isJoiError(error)) {
|
||||||
payload = (<ValidationError>error).details;
|
//Joi => error.details
|
||||||
} else {
|
payload = (<ValidationError>error).details;
|
||||||
// UseCaseError
|
} else {
|
||||||
/*const useCaseError = <UseCaseError>error;
|
// UseCaseError
|
||||||
|
/*const useCaseError = <UseCaseError>error;
|
||||||
if (useCaseError.payload.path) {
|
if (useCaseError.payload.path) {
|
||||||
const errorItem = {};
|
const errorItem = {};
|
||||||
errorItem[`${useCaseError.payload.path}`] = useCaseError.message;
|
errorItem[`${useCaseError.payload.path}`] = useCaseError.message;
|
||||||
@ -48,7 +49,8 @@ export function handleInfrastructureError(
|
|||||||
errors: [errorItem],
|
errors: [errorItem],
|
||||||
};
|
};
|
||||||
}*/
|
}*/
|
||||||
payload = (<UseCaseError>error).payload;
|
payload = (<UseCaseError>error).payload;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(payload);
|
console.log(payload);
|
||||||
|
|||||||
@ -40,7 +40,7 @@ export class FirebirdAdapter implements IFirebirdAdapter {
|
|||||||
|
|
||||||
protected constructor(
|
protected constructor(
|
||||||
connection: Firebird.ConnectionPool,
|
connection: Firebird.ConnectionPool,
|
||||||
queryBuilder: IRepositoryQueryBuilder
|
queryBuilder: IRepositoryQueryBuilder,
|
||||||
) {
|
) {
|
||||||
this._connection = connection;
|
this._connection = connection;
|
||||||
this._queryBuilder = queryBuilder;
|
this._queryBuilder = queryBuilder;
|
||||||
|
|||||||
@ -1,11 +1,11 @@
|
|||||||
import Firebird from "node-firebird";
|
import Firebird from "node-firebird";
|
||||||
import { TBusinessTransaction } from "../../domain/repositories";
|
import { IBusinessTransaction } from "../../domain/repositories";
|
||||||
import { InfrastructureError } from "../InfrastructureError";
|
import { InfrastructureError } from "../InfrastructureError";
|
||||||
|
|
||||||
export type FirebirdBusinessTransactionType = TBusinessTransaction & {
|
export type FirebirdBusinessTransactionType = IBusinessTransaction & {
|
||||||
start: (a: unknown) => unknown;
|
start: (a: unknown) => unknown;
|
||||||
complete(
|
complete(
|
||||||
work: (t: Firebird.Transaction, db: Firebird.Database) => unknown
|
work: (t: Firebird.Transaction, db: Firebird.Database) => unknown,
|
||||||
): void;
|
): void;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -23,7 +23,7 @@ export class FirebirdBusinessTransaction
|
|||||||
}
|
}
|
||||||
|
|
||||||
public complete(
|
public complete(
|
||||||
work: (t: Firebird.Transaction, db?: Firebird.Database) => unknown
|
work: (t: Firebird.Transaction, db?: Firebird.Database) => unknown,
|
||||||
): void {
|
): void {
|
||||||
this._connection.get((err, db: Firebird.Database) => {
|
this._connection.get((err, db: Firebird.Database) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
@ -36,7 +36,7 @@ export class FirebirdBusinessTransaction
|
|||||||
if (err) {
|
if (err) {
|
||||||
InfrastructureError.create(
|
InfrastructureError.create(
|
||||||
InfrastructureError.UNEXCEPTED_ERROR,
|
InfrastructureError.UNEXCEPTED_ERROR,
|
||||||
err
|
err,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -48,7 +48,7 @@ export class FirebirdBusinessTransaction
|
|||||||
} finally {
|
} finally {
|
||||||
db.detach();
|
db.detach();
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
import { config } from "@/config";
|
import { config } from "@/config";
|
||||||
import rTracer from "cls-rtracer";
|
import rTracer from "cls-rtracer";
|
||||||
import { DataTypes, Sequelize } from "sequelize";
|
import { DataTypes, Sequelize } from "sequelize";
|
||||||
import { SequelizeRevision } from "sequelize-revision";
|
|
||||||
|
|
||||||
import { initLogger } from "@/infrastructure/logger";
|
import { initLogger } from "@/infrastructure/logger";
|
||||||
import * as glob from "glob";
|
import * as glob from "glob";
|
||||||
@ -43,38 +42,23 @@ export class SequelizeAdapter implements ISequelizeAdapter {
|
|||||||
const { queryBuilder } = params;
|
const { queryBuilder } = params;
|
||||||
|
|
||||||
const connection = initConnection();
|
const connection = initConnection();
|
||||||
const sequelizeRevision = new SequelizeRevision(connection, {
|
const models = registerModels(connection);
|
||||||
UUID: true,
|
|
||||||
tableName: "revisions",
|
|
||||||
//changeTableName: "",
|
|
||||||
underscored: true,
|
|
||||||
underscoredAttributes: true,
|
|
||||||
});
|
|
||||||
const models = registerModels(connection, sequelizeRevision);
|
|
||||||
|
|
||||||
return new SequelizeAdapter(
|
return new SequelizeAdapter(connection, models, queryBuilder);
|
||||||
connection,
|
|
||||||
models,
|
|
||||||
queryBuilder,
|
|
||||||
sequelizeRevision
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private _connection: Sequelize;
|
private _connection: Sequelize;
|
||||||
private _models: ISequelizeModels;
|
private _models: ISequelizeModels;
|
||||||
private _queryBuilder: ISequelizeQueryBuilder;
|
private _queryBuilder: ISequelizeQueryBuilder;
|
||||||
private _revisions: SequelizeRevision<any>;
|
|
||||||
|
|
||||||
protected constructor(
|
protected constructor(
|
||||||
connection: Sequelize,
|
connection: Sequelize,
|
||||||
models: ISequelizeModels,
|
models: ISequelizeModels,
|
||||||
queryBuilder: ISequelizeQueryBuilder,
|
queryBuilder: ISequelizeQueryBuilder,
|
||||||
revisions: SequelizeRevision<any>
|
|
||||||
) {
|
) {
|
||||||
this._connection = connection;
|
this._connection = connection;
|
||||||
this._models = models;
|
this._models = models;
|
||||||
this._queryBuilder = queryBuilder;
|
this._queryBuilder = queryBuilder;
|
||||||
this._revisions = revisions;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
get queryBuilder(): ISequelizeQueryBuilder {
|
get queryBuilder(): ISequelizeQueryBuilder {
|
||||||
@ -95,7 +79,7 @@ export class SequelizeAdapter implements ISequelizeAdapter {
|
|||||||
}
|
}
|
||||||
throw InfrastructureError.create(
|
throw InfrastructureError.create(
|
||||||
InfrastructureError.RESOURCE_NOT_FOUND_ERROR,
|
InfrastructureError.RESOURCE_NOT_FOUND_ERROR,
|
||||||
`[SequelizeAdapter] ${modelName} sequelize model not exists!`
|
`[SequelizeAdapter] ${modelName} sequelize model not exists!`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -139,10 +123,7 @@ function initConnection(): Sequelize {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function registerModels(
|
function registerModels(connection: Sequelize): ISequelizeModels {
|
||||||
connection: Sequelize,
|
|
||||||
sequelizeRevision: SequelizeRevision<any>
|
|
||||||
): ISequelizeModels {
|
|
||||||
const cwd = path.resolve(`${__dirname}/../../../`);
|
const cwd = path.resolve(`${__dirname}/../../../`);
|
||||||
const models: ISequelizeModels = {};
|
const models: ISequelizeModels = {};
|
||||||
|
|
||||||
@ -164,18 +145,9 @@ function registerModels(
|
|||||||
if (model) models[model.name] = model;
|
if (model) models[model.name] = model;
|
||||||
});
|
});
|
||||||
|
|
||||||
// Register revisions models
|
|
||||||
const [Revision, RevisionChanges] = sequelizeRevision.defineModels();
|
|
||||||
//models[Revision.name] = Revision;
|
|
||||||
//models[RevisionChanges.name] = RevisionChanges;
|
|
||||||
|
|
||||||
for (const modelName in models) {
|
for (const modelName in models) {
|
||||||
const model = models[modelName];
|
const model = models[modelName];
|
||||||
|
|
||||||
if (model.trackRevision) {
|
|
||||||
model.trackRevision(connection, sequelizeRevision);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (model.associate) {
|
if (model.associate) {
|
||||||
model.associate(connection, models);
|
model.associate(connection, models);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,9 +1,8 @@
|
|||||||
import { Sequelize, Transaction } from "sequelize";
|
import { Sequelize, Transaction } from "sequelize";
|
||||||
import { TBusinessTransaction } from "../../domain/repositories";
|
import { TBusinessTransaction } from "../../domain";
|
||||||
import { InfrastructureError } from "../InfrastructureError";
|
import { InfrastructureError } from "../InfrastructureError";
|
||||||
|
|
||||||
export type SequelizeBusinessTransactionType = TBusinessTransaction & {
|
export type SequelizeBusinessTransactionType = TBusinessTransaction & {
|
||||||
start(): void;
|
|
||||||
complete<T>(work: (t: Transaction) => Promise<T>): Promise<T>;
|
complete<T>(work: (t: Transaction) => Promise<T>): Promise<T>;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -57,7 +56,7 @@ export class SequelizeBusinessTransaction
|
|||||||
|
|
||||||
throw InfrastructureError.create(
|
throw InfrastructureError.create(
|
||||||
InfrastructureError.UNEXCEPTED_ERROR,
|
InfrastructureError.UNEXCEPTED_ERROR,
|
||||||
(error as Error).message
|
(error as Error).message,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,4 @@
|
|||||||
import { Model, Sequelize } from "sequelize";
|
import { Model, Sequelize } from "sequelize";
|
||||||
import { SequelizeRevision } from "sequelize-revision";
|
|
||||||
|
|
||||||
interface ISequelizeModel extends Model {}
|
interface ISequelizeModel extends Model {}
|
||||||
|
|
||||||
@ -9,10 +8,6 @@ interface ISequelizeModels {
|
|||||||
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;
|
||||||
trackRevision?: (
|
|
||||||
connection: Sequelize,
|
|
||||||
sequelizeRevision: SequelizeRevision<any>
|
|
||||||
) => void;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export { ISequelizeModel, ISequelizeModels };
|
export { ISequelizeModel, ISequelizeModels };
|
||||||
|
|||||||
@ -1,3 +1,8 @@
|
|||||||
export interface ILogin_Response_DTO {
|
export interface ILogin_Response_DTO {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
email: string;
|
||||||
|
roles: string[];
|
||||||
token: string;
|
token: string;
|
||||||
|
refresh_token: string;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -33,7 +33,7 @@ export class QuickSearchCriteria
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return Result.ok(String(searchString));
|
return Result.ok(searchString);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static create(value: UndefinedOr<string>) {
|
public static create(value: UndefinedOr<string>) {
|
||||||
@ -49,7 +49,7 @@ export class QuickSearchCriteria
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static sanitize(searchTerm: UndefinedOr<string>): string {
|
private static sanitize(searchTerm: UndefinedOr<string>): string {
|
||||||
return String(Joi.string().trim().validate(searchTerm).value);
|
return String(Joi.string().default("").trim().validate(searchTerm).value);
|
||||||
}
|
}
|
||||||
|
|
||||||
get searchTerm(): string {
|
get searchTerm(): string {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user