Orders con endpoints para monitorizacion
This commit is contained in:
110
packages/sim-entrada-eventos/aplication/Order.controller.ts
Normal file
110
packages/sim-entrada-eventos/aplication/Order.controller.ts
Normal file
@@ -0,0 +1,110 @@
|
||||
import { BodyValidator } from "sim-shared/aplication/BodyValidator.js"
|
||||
import { OrderUsecases } from "./Order.usecases.js"
|
||||
import { Request, Response } from "express"
|
||||
import { PaginationArgs } from "#domain/common.js"
|
||||
|
||||
export class OrderController {
|
||||
private orderUseCases: OrderUsecases
|
||||
|
||||
constructor(args: {
|
||||
orderUseCases: OrderUsecases
|
||||
}) {
|
||||
this.orderUseCases = args.orderUseCases
|
||||
}
|
||||
|
||||
public getById(args: { id: number }) {
|
||||
return this.controllerGenerator<{ id: number }, { id: number }>({
|
||||
validator: undefined,
|
||||
useCase: this.orderUseCases.getById(args),
|
||||
onError: (data, error) => { console.error(error) },
|
||||
onSuccess: (data) => console.log(data)
|
||||
})
|
||||
}
|
||||
|
||||
public getPending(args: PaginationArgs) {
|
||||
return this.controllerGenerator<{ id: number }, { id: number }>({
|
||||
validator: undefined,
|
||||
useCase: this.orderUseCases.getPending(args),
|
||||
onError: (data, error) => { console.error(error) },
|
||||
onSuccess: (data) => console.log(data)
|
||||
})
|
||||
}
|
||||
|
||||
public getByQueueId(args: { message_id: string }) {
|
||||
return this.controllerGenerator({
|
||||
validator: undefined,
|
||||
useCase: this.orderUseCases.getByQueueId(args),
|
||||
onError: (data, error) => { console.error(error) },
|
||||
onSuccess: (data) => console.log(data)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* TODO:
|
||||
* - En proceso de validacion, tiene varios problemas
|
||||
* - Está copiado, planteado inyectarlo
|
||||
*
|
||||
* Abstrae el proceso de
|
||||
* Peticion -> validacion del body -> map del body -> useCase -> OK/ERR
|
||||
*
|
||||
* <O> Representa el dato original
|
||||
* <P> Representa el dato después del mapeo
|
||||
*/
|
||||
public controllerGenerator<O extends Object, P extends Object>(args: {
|
||||
validator?: BodyValidator<O>,
|
||||
mapBody?: (body: O) => P,
|
||||
useCase: (args: P) => Promise<any>,
|
||||
onError: (args: O | P, error: string) => void,
|
||||
onSuccess: (args: P) => void,
|
||||
}) {
|
||||
return async (req: Request, res: Response) => {
|
||||
const body = req.body
|
||||
|
||||
// 1. Validacion del body
|
||||
try {
|
||||
if (args.validator != undefined)
|
||||
args.validator.validate(body)
|
||||
} catch (e) {
|
||||
if (args.onError != undefined) args.onError(body, e as string)
|
||||
res.status(422).json({
|
||||
errors: {
|
||||
msg: e
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 2. Transformacion del body
|
||||
let data: P = body;
|
||||
try {
|
||||
if (args.mapBody != undefined)
|
||||
data = args.mapBody(body)
|
||||
} catch (e) {
|
||||
res.status(422).json({
|
||||
errors: {
|
||||
msg: "Error parseando el body: " + e
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 3. Aplicacion del UseCase
|
||||
try {
|
||||
const usecaseResult = await args.useCase(data)
|
||||
// 4. Se devuelve al usuario el caso de exito
|
||||
res.status(200).json(
|
||||
usecaseResult
|
||||
).send()
|
||||
args.onSuccess(data)
|
||||
} catch (err) {
|
||||
// 4.1 Error del caso de uso
|
||||
res.status(500).json({
|
||||
errors: {
|
||||
msg: "Error general:" + err
|
||||
}
|
||||
}).send()
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
37
packages/sim-entrada-eventos/aplication/Order.usecases.ts
Normal file
37
packages/sim-entrada-eventos/aplication/Order.usecases.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
import { PaginationArgs } from "#domain/common.js";
|
||||
import { OrderRepository } from "sim-shared/infrastructure/OrderRepository.js";
|
||||
|
||||
|
||||
export class OrderUsecases {
|
||||
private orderRepository: OrderRepository;
|
||||
constructor(args: {
|
||||
orderRepository: OrderRepository
|
||||
}
|
||||
) {
|
||||
this.orderRepository = args.orderRepository
|
||||
}
|
||||
|
||||
public getById(args: {
|
||||
id: number
|
||||
}) {
|
||||
return async () => {
|
||||
return await this.orderRepository.getOrderById(args)
|
||||
}
|
||||
}
|
||||
|
||||
public getByQueueId(args: {
|
||||
message_id: string
|
||||
}) {
|
||||
return async () => {
|
||||
return await this.orderRepository.getOrderByQueueId(args)
|
||||
}
|
||||
}
|
||||
|
||||
public getPending(args: PaginationArgs & {
|
||||
}) {
|
||||
return async () => {
|
||||
return await this.orderRepository.getPendingOrders(args)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -3,7 +3,6 @@ import { SimUsecases } from "./Sim.usecases.js"
|
||||
import { activationValidator, iccidValidator } from "./httpValidators.js"
|
||||
import { companyFromIccid } from "#domain/companies.js"
|
||||
import { BodyValidator } from "sim-shared/aplication/BodyValidator.js"
|
||||
import { error } from "node:console"
|
||||
|
||||
|
||||
export class SimController {
|
||||
@@ -30,7 +29,7 @@ export class SimController {
|
||||
public controllerGenerator<O extends Object, P extends Object>(args: {
|
||||
validator?: BodyValidator<O>,
|
||||
mapBody?: (body: O) => P,
|
||||
useCase: (args: P) => Promise<void>,
|
||||
useCase: (args: P) => Promise<any>,
|
||||
onError: (args: O | P, error: string) => void,
|
||||
onSuccess: (args: P) => void,
|
||||
}) {
|
||||
@@ -66,10 +65,13 @@ export class SimController {
|
||||
// 3. Aplicacion del UseCase
|
||||
try {
|
||||
const usecaseResult = await args.useCase(data)
|
||||
// 4. Se devuelve al usuario el caso de exito
|
||||
res.status(200).json(
|
||||
usecaseResult
|
||||
).send()
|
||||
args.onSuccess(data)
|
||||
} catch (err) {
|
||||
// 4.1 Error del caso de uso
|
||||
res.status(500).json({
|
||||
errors: {
|
||||
msg: "Error general:" + err
|
||||
@@ -77,13 +79,14 @@ export class SimController {
|
||||
}).send()
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public preactivationTest() {
|
||||
return this.controllerGenerator({
|
||||
public test() {
|
||||
return this.controllerGenerator<{ iccid: string, offer: string }, { iccid: string }>({
|
||||
validator: iccidValidator,
|
||||
useCase: this.simUseCases.test,
|
||||
useCase: (args) => this.simUseCases.test(args),
|
||||
onError: (data, error) => console.error(error),
|
||||
onSuccess: (data) => {
|
||||
console.log("OK", data)
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import { OrderRepository } from "sim-shared/infrastructure/OrderRepository.js";
|
||||
import { Result } from "sim-shared/domain/Result.js";
|
||||
import assert from "node:assert";
|
||||
import { EventBus } from "sim-shared/domain/EventBus.port";
|
||||
import { SimEvents } from "sim-shared/domain/SimEvents";
|
||||
import { uuidv7 } from "uuidv7";
|
||||
import { CreateOrderDTO, OrderType } from "sim-shared/domain/Order.js";
|
||||
import { CreateOrderDTO, OrderTracking, OrderType, OrderTypeOptions } from "sim-shared/domain/Order.js";
|
||||
|
||||
/**
|
||||
* Casos de uso de tarjetas sim. Garantiza que todos los metodos usan el mismo bus de mensajes
|
||||
@@ -22,40 +23,61 @@ export class SimUsecases {
|
||||
this.orderRepository = args.orderRepository
|
||||
}
|
||||
|
||||
|
||||
async test(args: { iccid: string }) {
|
||||
assert(args.iccid != undefined)
|
||||
private addMessage_id(event: SimEvents.general): SimEvents.general & { headers: { message_id: string } } {
|
||||
const uuid = uuidv7()
|
||||
const event = <SimEvents.general>{
|
||||
key: `sim.test.test`,
|
||||
payload: {
|
||||
iccid: args.iccid
|
||||
},
|
||||
return {
|
||||
...event,
|
||||
headers: {
|
||||
...event.headers,
|
||||
message_id: uuid
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const publish = await this.eventBus.publish([event])
|
||||
|
||||
/**
|
||||
* TODO:
|
||||
* De momento solo para mensajes publicados de 1 en 1 y si se les ha añadido cabecera
|
||||
* Si se ha saltado el proceso de añadir un ID no se
|
||||
*/
|
||||
if (publish.success.length == 1) {
|
||||
if (event.headers?.message_id != undefined) {
|
||||
const orderType = (event.key.split(".")[2] as OrderType ?? "unknown")
|
||||
assert(orderType)
|
||||
const order: CreateOrderDTO = {
|
||||
correlation_id: event.headers.message_id,
|
||||
order_type: orderType,
|
||||
routing_key: event.key,
|
||||
payload: event
|
||||
}
|
||||
this.orderRepository.createOrder(order)
|
||||
/**
|
||||
* El tipo T es el tipo del payload del Order
|
||||
*/
|
||||
private async saveOrder<T extends any>(event: SimEvents.general): Promise<Result<string, OrderTracking<T>>> {
|
||||
if (event.headers?.message_id == undefined) {
|
||||
return <Result<string, any>>{
|
||||
error: "El evento no tiene una cabecera message_id definido"
|
||||
}
|
||||
}
|
||||
|
||||
const orderType = (event.key.split(".")[2] as OrderType ?? "unknown")
|
||||
|
||||
// Estoy pensando en la posibilidad de pasarlo a unknown
|
||||
if (!OrderTypeOptions.has(orderType)) {
|
||||
return <Result<string, any>>{
|
||||
error: `El evento no tiene un tipo valido: ${orderType} no existe como tipo valido`
|
||||
}
|
||||
}
|
||||
|
||||
const order: CreateOrderDTO = {
|
||||
correlation_id: event.headers.message_id,
|
||||
order_type: orderType,
|
||||
routing_key: event.key,
|
||||
payload: event
|
||||
}
|
||||
|
||||
const result = await this.orderRepository.createOrder<T>(order)
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
async test(args: { iccid: string }) {
|
||||
assert(args.iccid != undefined)
|
||||
const event = <SimEvents.general>{
|
||||
key: `sim.test.unknown`,
|
||||
payload: {
|
||||
iccid: args.iccid
|
||||
}
|
||||
}
|
||||
const eventWithId = this.addMessage_id(event)
|
||||
|
||||
const publish = await this.eventBus.publish([eventWithId])
|
||||
await this.saveOrder(eventWithId)
|
||||
return eventWithId
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -85,8 +107,11 @@ export class SimUsecases {
|
||||
offer: args.offer
|
||||
}
|
||||
}
|
||||
console.log("[d] Activation ", activationEvent)
|
||||
return this.eventBus.publish([activationEvent])
|
||||
|
||||
const activationWithId = this.addMessage_id(activationEvent)
|
||||
console.log("[d] Activation ", activationWithId)
|
||||
await this.eventBus.publish([activationWithId])
|
||||
this.saveOrder(activationWithId)
|
||||
}
|
||||
|
||||
async preActivation(args: { iccid: string, compañia: string }) {
|
||||
|
||||
6
packages/sim-entrada-eventos/domain/common.ts
Normal file
6
packages/sim-entrada-eventos/domain/common.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
|
||||
export type PaginationArgs = {
|
||||
limit?: number,
|
||||
offset?: number,
|
||||
start?: number
|
||||
}
|
||||
@@ -3,6 +3,7 @@ import cors from 'cors';
|
||||
import { simRoutes } from "./infrastructure/simRoutes.http.js"
|
||||
import { rabbitmqEventBus } from '#config/eventBusConfig.js';
|
||||
import { env } from "#config/env/index.js"
|
||||
import { orderRoutes } from "#adapters/orderRoutes.http.js";
|
||||
|
||||
const PORT = env.API_PORT
|
||||
const HOSTNAME = "0.0.0.0"
|
||||
@@ -24,6 +25,7 @@ app.use(express.json());
|
||||
app.use(express.urlencoded({ extended: true }));
|
||||
|
||||
app.use("/sim", simRoutes)
|
||||
app.use("/orders", orderRoutes)
|
||||
|
||||
app.get("/health", (req, res) => {
|
||||
res.status(200).json({ status: "ok" })
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
/**
|
||||
* Rutas para consultar el estado de los order
|
||||
*/
|
||||
|
||||
import { OrderRepository } from "sim-shared/infrastructure/OrderRepository.js"
|
||||
import { Router } from "express"
|
||||
import { postgresClient } from '#config/postgreConfig.js';
|
||||
|
||||
const orderRoutes = Router()
|
||||
// orderRepository no se trata como singleton
|
||||
const orderRepository = new OrderRepository(postgresClient)
|
||||
|
||||
/**
|
||||
* Todas las orders, o un resumen, admite filtros
|
||||
* por:
|
||||
* - status
|
||||
* - fecha inicio
|
||||
* - fecha fin
|
||||
* - pendientes
|
||||
* */
|
||||
orderRoutes.get("/")
|
||||
|
||||
/** Order por id (uuid del mensaje) */
|
||||
orderRoutes.get("/{id}")
|
||||
|
||||
orderRoutes.get("/{status}")
|
||||
|
||||
|
||||
export { orderRoutes }
|
||||
|
||||
|
||||
@@ -30,6 +30,8 @@ simRoutes.post("/pause", simController.pause())
|
||||
|
||||
simRoutes.post("/cancel", simController.cancelation())
|
||||
|
||||
simRoutes.post("/test", simController.test())
|
||||
|
||||
// Proceso especifico de ALAI para liberar sims canceladas
|
||||
simRoutes.post("/free", simController.free())
|
||||
|
||||
|
||||
@@ -13,12 +13,6 @@
|
||||
"types": "./config/*.ts",
|
||||
"default": "./config/*.js"
|
||||
},
|
||||
"#shared/*.js": {
|
||||
"default": "../sim-shared/*.js"
|
||||
},
|
||||
"#shared/*": {
|
||||
"default": "../sim-shared/*.js"
|
||||
},
|
||||
"#adapters/*.js": {
|
||||
"types": "./infrastructure/*.ts",
|
||||
"default": "./infrastructure/*.js"
|
||||
|
||||
Reference in New Issue
Block a user