import { Request, Response } from "express" 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 { tryCatch } from "sim-shared/domain/Result.js" import { mapCompanyService } from "#config/servicesProxy.js" import axios, { AxiosError, isAxiosError } from "axios" export class SimController { private simUseCases: SimUsecases constructor(args: { simUseCases: SimUsecases, }) { this.simUseCases = args.simUseCases this.activation = this.activation.bind(this) } /** * TODO: * En proceso, tiene varios problemas * * Abstrae el proceso de * Peticion -> validacion del body -> map del body -> useCase -> OK/ERR * * Representa el dato original *

Representa el dato después del mapeo */ public controllerGenerator(args: { validator?: BodyValidator, mapBody?: (body: O) => P, useCase: (args: P) => Promise, 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 if (args.validator != undefined) { const validationResult = args.validator.validate(body) if (validationResult.error != undefined) { res.status(422).json({ errors: { ...validationResult.error } }) args.onError(body, validationResult.error.msg) return 1; } } // 2. Transformacion del body // TODO: sustituir el try cach 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 } }) args.onError(body, String(e)) return 1; } // 3. Aplicacion del UseCase // TODO: todos los use cases tienen que pasar a devolver un Result<> const usecaseResult = await args.useCase(data) // no deberia hacer falta el trycatch // 4. Casos de error del usecase if (usecaseResult.error != undefined) { // 4.1 Error del caso de uso res.status(500).json({ errors: { ...usecaseResult.error } }).send() args.onError(body, usecaseResult.error ?? "Error indefinido") return 1; } // 5. Se devuelve al usuario el caso de exito res.status(200).json( usecaseResult.data ).send() args.onSuccess(usecaseResult.data) return 0; } } public test() { return this.controllerGenerator<{ iccid: string, offer: string }, { iccid: string }>({ validator: iccidValidator, useCase: (args) => this.simUseCases.test(args), onError: (data, error) => console.error(error), onSuccess: (data) => { console.log("OK", data) } }) } public preactivation() { return this.controllerGenerator<{ iccid: string, offer: string }, { iccid: string, offer: string, compañia: string }>({ validator: activationValidator, mapBody: (b) => { const { iccid, offer } = b const compañia = companyFromIccid(iccid) return { iccid, compañia, offer } }, useCase: (args) => this.simUseCases.preActivation(args), onError: (d, e) => console.error("[x] Error preactivation: ", d, e), onSuccess: console.log }) } public activation() { return this.controllerGenerator<{ iccid: string, offer: string }, { iccid: string, offer: string, compañia: string }>({ validator: activationValidator, mapBody: (b) => { const { iccid, offer } = b const compañia = companyFromIccid(iccid) return { iccid, compañia, offer } }, useCase: (args) => this.simUseCases.activation(args), onError: (d, e) => console.error("[x] Error activacion: ", d, e), onSuccess: console.log }) } public reActivation() { return this.controllerGenerator<{ iccid: string, offer: string }, { iccid: string, offer: string, compañia: string }>({ validator: iccidValidator, mapBody: (b) => { const { iccid, offer } = b const compañia = companyFromIccid(iccid) return { iccid, compañia, offer } }, useCase: (args) => this.simUseCases.reActivation(args), onError: (d, e) => console.error("[x] Error reactivacion: ", d, e), onSuccess: console.log }) } public cancelation() { return this.controllerGenerator<{ iccid: string }, { iccid: string, compañia: string }>({ validator: iccidValidator, mapBody: (b) => { const { iccid } = b const compañia = companyFromIccid(iccid) return { iccid, compañia } }, useCase: (args) => this.simUseCases.cancelation(args), // TODO: Meter en los mensajes el nombre de la operacion onError: (d, e) => console.error("[x] Error cancelacion: ", d, e), onSuccess: console.log }) } public pause() { return this.controllerGenerator<{ iccid: string }, { iccid: string, compañia: string }>({ validator: iccidValidator, mapBody: (b) => { const { iccid } = b const compañia = companyFromIccid(iccid) return { iccid, compañia } }, useCase: (args) => this.simUseCases.pause(args), onError: (d, e) => console.error("[x] Error pausa: ", d, e), onSuccess: console.log }) } public free() { return async (req: Request, res: Response) => { try { iccidValidator.validate(req.body) } catch (e) { res.status(422).json({ errors: { msg: e } }) } const { iccid } = req.body const compañia = companyFromIccid(iccid) try { await this.simUseCases.cancelation({ iccid, compañia }) res.status(200).json({ iccid: iccid, operation: "liberacion" }) } catch (err) { console.error("Error liberando la sim ", req.body) res.status(500).json({ errors: { msg: "Error general de liberacion" } }) } } } /** * Select no pasa por la cola de eventos al ser de solo lectura. * Cada uno de los servicios de los proveedores tiene que aderirse al * modelo común de datos de SIM + campo "raw" * * De momento se va a buscar por iccid, mas adlante por movil u otro criterio */ public select() { return async (req: Request, res: Response) => { console.log("SELECT: ", req.query) const iccid = req.query.iccid as string const validationRes = iccidValidator.validate({ iccid: iccid }) if (validationRes.error != undefined) { res.status(422).json({ errors: { ...validationRes.error } }) return; } const company = companyFromIccid(iccid) const url = mapCompanyService.get(company) const endpoint = "/select" if (url == undefined) { console.error("[x] Error buscando el servicio para el select del iccid ", iccid) } try { const respSelect = await axios.get(url + endpoint, { params: req.query }) res.json(respSelect.data) } catch (err) { if (isAxiosError(err)) { const axiosErr = err as AxiosError res.status(axiosErr.status ?? 500).json(err) } else { res.status(500).json({ errors: { msg: "Error general buscando la sim" } }) } } } } /** * -- WIP * Esta funcion se plantea para guardar tarjetas que no han llegado desde * un operador conocido */ public save() { return async (req: Request, res: Response) => { try { iccidValidator.validate(req.body) } catch (e) { res.status(422).json({ errors: { msg: e } }) } const { iccid } = req.body const compañia = companyFromIccid(iccid) try { await this.simUseCases.cancelation({ iccid, compañia }) res.status(200).json({ iccid: iccid, operation: "cancelation" }) } catch (err) { console.error("Error activando la sim ", req.body) res.status(500).json({ errors: { msg: "Error general de activation" } }) } } } }