Validaciones para los endpints

This commit is contained in:
2026-02-10 15:57:03 +01:00
parent 70ef1131df
commit a39b84e107
13 changed files with 175 additions and 48 deletions

1
.env
View File

@@ -1,4 +1,5 @@
PORT=3000
API_HOSTNAME=0.0.0.0
RABBITMQ_USER=guest
RABBITMQ_PASSWORD=guest

View File

@@ -5,4 +5,6 @@ OBJ_CLI_ASSERTION=XOc7FtwXD8hUX2SFVX94XSty8wkOmChkwDNF09O_aIxPubMDdFUdCDCB4zpzSI
OBJ_CLIENT_ID=savefamily_rest_ws
OBJ_KID=xNfbMiyL1ORXGP8lElhcv8nVaG3EJKye4Lc1YoN3I1E
OBJ_BASE_URL=https://api-getway.objenious.com/ws
OBJ_CUSTOMER_CODE=9.49411.10
//OBJ_BASE_URL=https://api-getway.objenious.com/ws/test

View File

@@ -3,6 +3,8 @@ import { ConsumeMessage } from "amqplib";
import { SimUseCases } from "./Sim.usecases.js";
import { SimEvents } from "sim-shared/domain/SimEvents.js";
import { Result } from "sim-shared/domain/Result.js";
import { env } from "#config/env/index.js";
import { s } from "node_modules/vitest/dist/chunks/reporters.d.CWXNI2jG.js";
/**
* La clase usa generadores de funciones para mantener el contexto
@@ -64,6 +66,8 @@ export class SimController {
}
public activate() {
const DUE_DATE_SECONDS = 2 * 60
return async (msg: ConsumeMessage) => {
let msgData;
try {
@@ -81,8 +85,8 @@ export class SimController {
}
this.tryUseCase(msg, this.useCases.activate({
dueDate: this.genDueDate(2 * 60).toISOString(),
customerAccountCode: "9.49411.10", // TODO: Al .env
dueDate: this.genDueDate(DUE_DATE_SECONDS).toISOString(),
customerAccountCode: env.OBJ_CUSTOMER_CODE,
identifier: {
identifierType: "ICCID",
identifiers: [iccid]
@@ -213,3 +217,4 @@ export class SimController {
return dueDate
}
}

View File

@@ -28,7 +28,7 @@ export const env = {
OBJ_CLI_ASSERTION: String(process.env.OBJ_CLI_ASSERTION),
OBJ_CLIENT_ID: String(process.env.OBJ_CLIENT_ID),
OBJ_KID: String(process.env.OBJ_KID),
OBJ_BASE_URL: String(process.env.OBJ_BASE_URL)
OBJ_BASE_URL: String(process.env.OBJ_BASE_URL),
OBJ_CUSTOMER_CODE: String(process.env.OBJ_CUSTOMER_CODE)
};

View File

@@ -68,7 +68,6 @@
"cors": "*",
"dotenv": "*",
"express": "*",
"sim-consumidor-objenious": "sim-consumidor-objenious:*",
"sim-shared": "sim-shared:*",
"typescript": "*"
},

View File

@@ -1,16 +1,8 @@
import { Request, Response } from "express"
import { SimUsecases } from "./Sim.usecases.js"
import { activationValidator, iccidValidator } from "./httpValidators.js"
import { companyFromIccid } from "#domain/companies.js"
// Partiendo del caracter 3 2 de pais + 2 de compañia
// Metiendolo a la BDD podria ser mas dinamico pero perderia
// tiempo de query
// Puede que esté bien crear un endpoint para administrarlo
const COMPAÑIASICCID = new Map<string, string>(
[
["3490", "alai"],
["3510", "nos"],
["3320", "objenious"]
])
export class SimController {
private simUseCases: SimUsecases
@@ -25,11 +17,19 @@ export class SimController {
public preactivation() {
return async (req: Request, res: Response) => {
const valido = this.validateBody(req.body, res)
if (valido == false) return;
console.warn("[!] Se deberia de usar la peticion /sim/activate directamente")
try {
iccidValidator.validate(req.body)
} catch (e) {
res.status(422).json({
errors: {
msg: e
}
})
}
const { iccid } = req.body
const compañia = this.compañiaFromIccid(iccid)
const compañia = companyFromIccid(iccid)
if (compañia == undefined) {
res.status(500).json({
@@ -62,13 +62,19 @@ export class SimController {
public activation() {
return async (req: Request, res: Response) => {
const valido = this.validateBody(req.body, res)
if (valido == false) return; // Si no es valido ya se ha enviado el error
try {
activationValidator.validate(req.body)
} catch (e) {
res.status(422).json({
errors: {
msg: e
}
})
}
const { iccid, offer } = req.body
const compañia = this.compañiaFromIccid(iccid)
const compañia = companyFromIccid(iccid)
if (compañia == undefined) {
res.status(500).json({
@@ -101,12 +107,18 @@ export class SimController {
public cancelation() {
return async (req: Request, res: Response) => {
const valido = this.validateBody(req.body, res)
if (valido == false) return; // Si no es valido ya se ha enviado el error
try {
iccidValidator.validate(req.body)
} catch (e) {
res.status(422).json({
errors: {
msg: e
}
})
}
const { iccid } = req.body
const compañia = this.compañiaFromIccid(iccid)
const compañia = companyFromIccid(iccid)
try {
await this.simUseCases.cancelation({ iccid, compañia })
@@ -127,12 +139,18 @@ export class SimController {
public pause() {
return async (req: Request, res: Response) => {
const valido = this.validateBody(req.body, res)
if (valido == false) return; // Si no es valido ya se ha enviado el error
try {
iccidValidator.validate(req.body)
} catch (e) {
res.status(422).json({
errors: {
msg: e
}
})
}
const { iccid } = req.body
const compañia = this.compañiaFromIccid(iccid)
const compañia = companyFromIccid(iccid)
try {
await this.simUseCases.pause({ iccid, compañia })
@@ -153,12 +171,18 @@ export class SimController {
public free() {
return async (req: Request, res: Response) => {
const valido = this.validateBody(req.body, res)
if (valido == false) return; // Si no es valido ya se ha enviado el error
try {
iccidValidator.validate(req.body)
} catch (e) {
res.status(422).json({
errors: {
msg: e
}
})
}
const { iccid } = req.body
const compañia = this.compañiaFromIccid(iccid)
const compañia = companyFromIccid(iccid)
try {
await this.simUseCases.cancelation({ iccid, compañia })
@@ -185,7 +209,7 @@ export class SimController {
if (valido == false) return; // Si no es valido ya se ha enviado el error
const { iccid } = req.body
const compañia = this.compañiaFromIccid(iccid)
const compañia = companyFromIccid(iccid)
try {
await this.simUseCases.cancelation({ iccid, compañia })
@@ -228,15 +252,4 @@ export class SimController {
return valid;
}
/**
* A partir del iccid completo devuelve la compañia a la que pertenece
* @throws Error si no hay una compañia definida en COMPAÑIASICCID con el codigo
*/
private compañiaFromIccid(iccid: string) {
const caracteresCommpañia = iccid.slice(2, 6)
const compañia = COMPAÑIASICCID.get(caracteresCommpañia)
if (compañia == undefined) throw new Error("El la compañia es desconocida: " + caracteresCommpañia)
return compañia
}
}

View File

@@ -0,0 +1,50 @@
import { companyFromIccid } from "#domain/companies.js";
import { BodyValidator, Validator } from "sim-shared/aplication/BodyValidator.js";
const offers = new Map([
["mensual", "SAVEFAMILY1"],
["anual", "SAVEFAMILY2"]
])
const iccidLongitudValidator = <Validator<{ iccid: string }>>{
field: "iccid",
errorMsg: "La longitud del iccid es incorrecta debera ser de 19 caracteres",
validationFunc: (a: { iccid: string }) => a.iccid.length == 19,
}
const iccidRequired = <Validator<{ iccid: string }>>{
field: "iccid",
errorMsg: "El iccid debe estara definido",
validationFunc: (a: { iccid: string }) => a.iccid != undefined,
}
const iccidWithValidCompany = <Validator<{ iccid: string }>>{
field: "iccid",
errorMsg: "El iccid no corresponde a una compañia registrada",
validationFunc: (a: { iccid: string }) => companyFromIccid(a.iccid) != undefined,
}
const offerExists = <Validator<{ offer: string }>>{
field: "offer",
errorMsg: "La oferta introducida no es valida",
validationFunc: (a: { offer: string }) => offers.has(a.offer),
}
export const activationValidator = new BodyValidator<{ iccid: string, offer: string }>(
[
iccidRequired,
iccidLongitudValidator,
iccidWithValidCompany,
offerExists,
]
)
export const iccidValidator = new BodyValidator<{ iccid: string, offer: string }>(
[
iccidRequired,
iccidLongitudValidator,
iccidWithValidCompany,
]
)

View File

@@ -0,0 +1,22 @@
// Partiendo del caracter 3 2 de pais + 2 de compañia
// Metiendolo a la BDD podria ser mas dinamico pero perderia
// tiempo de query
// Puede que esté bien crear un endpoint para administrarlo
export const COMPANYICCID = new Map<string, string>(
[
["3490", "alai"],
["3510", "nos"],
["3320", "objenious"]
])
/**
* A partir del iccid completo devuelve la compañia a la que pertenece
* @throws Error si no hay una compañia definida en COMPAÑIASICCID con el codigo
*/
export function companyFromIccid(iccid: string) {
const caracteresCommpañia = iccid.slice(2, 6)
const compañia = COMPANYICCID.get(caracteresCommpañia)
if (compañia == undefined) throw new Error("El la compañia es desconocida: " + caracteresCommpañia)
return compañia
}

View File

@@ -13,6 +13,7 @@ const simController = new SimController({
simUseCases: simUseCases
})
// TODO: status de todos los proyectos
simRoutes.get("/status", () => { })
simRoutes.post("/save", simController.save())

View File

@@ -59,6 +59,7 @@
"cors": "*",
"dotenv": "*",
"express": "*",
"sim-shared": "sim-shared:*",
"typescript": "*"
},
"devDependencies": {

View File

@@ -0,0 +1,25 @@
export type Validator<T extends Object> = {
field: keyof T,
errorMsg: string,
validationFunc: (obj: T) => boolean
}
/**
* Ejecuta una lista de validadores en orden, si alguno
* falla devuelve un Error
*/
export class BodyValidator<T extends Object> {
validatorList: Validator<T>[] = []
constructor(
validators: Validator<T>[]
) {
this.validatorList = validators
}
public validate(obj: T) {
for (const validator of this.validatorList) {
if (validator.validationFunc(obj) == false) throw new Error(validator.errorMsg)
}
return true;
}
}

View File

@@ -4,6 +4,14 @@
"version": "1.0.0",
"description": "",
"exports": {
"./aplication/*.js": {
"types": "./aplication/*.ts",
"default": "./aplication/*.js"
},
"./aplication/*": {
"types": "./aplication/*.ts",
"default": "./aplication/*.js"
},
"./infrastructure/*.js": {
"types": "./infrastructure/*.ts",
"default": "./infrastructure/*.js"

View File

@@ -2769,7 +2769,7 @@ __metadata:
languageName: unknown
linkType: soft
"sim-consumidor-objenious@sim-consumidor-objenious:*, sim-consumidor-objenious@workspace:packages/sim-consumidor-objenious":
"sim-consumidor-objenious@workspace:packages/sim-consumidor-objenious":
version: 0.0.0-use.local
resolution: "sim-consumidor-objenious@workspace:packages/sim-consumidor-objenious"
dependencies:
@@ -2784,7 +2784,6 @@ __metadata:
dotenv: "npm:*"
express: "npm:*"
prettier: "npm:*"
sim-consumidor-objenious: "sim-consumidor-objenious:*"
sim-shared: "sim-shared:*"
supertest: "npm:*"
tsc-alias: "npm:^1.8.16"
@@ -2809,6 +2808,7 @@ __metadata:
dotenv: "npm:*"
express: "npm:*"
prettier: "npm:*"
sim-shared: "sim-shared:*"
supertest: "npm:*"
tsc-alias: "npm:^1.8.16"
tsx: "npm:*"