package controllers import ( "math" "strconv" "strings" "github.com/gofiber/fiber/v2" "github.com/sujit-baniya/fiber-boilerplate/pkg/models" ) // ─── Panel: lista de configuraciones ───────────────────────────────────────── // SaasApiIndex renderiza la vista del panel de integraciones SaaS. func SaasApiIndex(c *fiber.Ctx) error { data := fiber.Map{ "user": c.Locals("user").(map[string]interface{}), "modules": c.Locals("userModules"), } if err := c.Render("saas_api", data, "layouts/main"); err != nil { return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": err.Error()}) } return nil } // GetSaasApiConfigs devuelve la lista paginada en JSON. func GetSaasApiConfigs(c *fiber.Ctx) error { page, _ := strconv.Atoi(c.Query("page", "1")) if page < 1 { page = 1 } limit := 20 offset := (page - 1) * limit items, total, err := models.GetAllSaasApiConfigs(limit, offset) if err != nil { return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": err.Error()}) } saasOpts, _ := models.GetAllSaasProductosSelect() return c.JSON(fiber.Map{ "items": items, "saas": saasOpts, "total": total, "totalPages": int(math.Ceil(float64(total) / float64(limit))), "page": page, "limit": limit, }) } // CreateSaasApiConfig crea una nueva configuración de integración. func CreateSaasApiConfig(c *fiber.Ctx) error { type Req struct { SaasID uint `json:"saas_id"` Nombre string `json:"nombre"` Pasarela string `json:"pasarela"` EndpointURL string `json:"endpoint_url"` Metodo string `json:"metodo"` ApiKeyHeader string `json:"api_key_header"` ApiKeyValue string `json:"api_key_value"` PayloadTemplate string `json:"payload_template"` TimeoutSeg int `json:"timeout_seg"` Activo bool `json:"activo"` } var req Req if err := c.BodyParser(&req); err != nil { return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "body inválido"}) } if req.SaasID == 0 { return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "saas_id es requerido"}) } if strings.TrimSpace(req.Nombre) == "" { return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "nombre es requerido"}) } if strings.TrimSpace(req.EndpointURL) == "" { return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "endpoint_url es requerido"}) } metodo := strings.ToUpper(strings.TrimSpace(req.Metodo)) if metodo == "" { metodo = "POST" } pasarela := strings.ToLower(strings.TrimSpace(req.Pasarela)) if pasarela == "" { pasarela = "ambas" } timeout := req.TimeoutSeg if timeout <= 0 { timeout = 10 } item := models.SaasApiConfig{ SaasID: req.SaasID, Nombre: req.Nombre, Pasarela: pasarela, EndpointURL: req.EndpointURL, Metodo: metodo, ApiKeyHeader: req.ApiKeyHeader, ApiKeyValue: req.ApiKeyValue, PayloadTemplate: req.PayloadTemplate, TimeoutSeg: timeout, Activo: req.Activo, } if err := models.CreateSaasApiConfig(&item); err != nil { return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": err.Error()}) } return c.Status(fiber.StatusCreated).JSON(item) } // UpdateSaasApiConfig actualiza una configuración existente. func UpdateSaasApiConfig(c *fiber.Ctx) error { idParam := c.Params("id") id64, err := strconv.ParseUint(idParam, 10, 64) if err != nil { return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "id inválido"}) } item, err := models.GetSaasApiConfigByID(uint(id64)) if err != nil { return c.Status(fiber.StatusNotFound).JSON(fiber.Map{"error": "no encontrado"}) } type Req struct { SaasID uint `json:"saas_id"` Nombre string `json:"nombre"` Pasarela string `json:"pasarela"` EndpointURL string `json:"endpoint_url"` Metodo string `json:"metodo"` ApiKeyHeader string `json:"api_key_header"` ApiKeyValue string `json:"api_key_value"` PayloadTemplate string `json:"payload_template"` TimeoutSeg int `json:"timeout_seg"` Activo bool `json:"activo"` } var req Req if err := c.BodyParser(&req); err != nil { return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "body inválido"}) } if req.SaasID != 0 { item.SaasID = req.SaasID } if strings.TrimSpace(req.Nombre) != "" { item.Nombre = req.Nombre } pasarela := strings.ToLower(strings.TrimSpace(req.Pasarela)) if pasarela != "" { item.Pasarela = pasarela } if strings.TrimSpace(req.EndpointURL) != "" { item.EndpointURL = req.EndpointURL } metodo := strings.ToUpper(strings.TrimSpace(req.Metodo)) if metodo != "" { item.Metodo = metodo } item.ApiKeyHeader = req.ApiKeyHeader // Solo actualizar api_key_value si se envió un valor (para no borrar el secreto con "") if req.ApiKeyValue != "" { item.ApiKeyValue = req.ApiKeyValue } item.PayloadTemplate = req.PayloadTemplate if req.TimeoutSeg > 0 { item.TimeoutSeg = req.TimeoutSeg } item.Activo = req.Activo if err := models.UpdateSaasApiConfig(item); err != nil { return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": err.Error()}) } return c.JSON(item) } // DeleteSaasApiConfig elimina una configuración. func DeleteSaasApiConfig(c *fiber.Ctx) error { idParam := c.Params("id") id64, err := strconv.ParseUint(idParam, 10, 64) if err != nil { return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "id inválido"}) } if err := models.DeleteSaasApiConfig(uint(id64)); err != nil { return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": err.Error()}) } return c.JSON(fiber.Map{"ok": true}) } // ─── Panel: logs de despacho ────────────────────────────────────────────────── // SaasDispatchLogIndex renderiza la vista de logs de despacho. func SaasDispatchLogIndex(c *fiber.Ctx) error { data := fiber.Map{ "user": c.Locals("user").(map[string]interface{}), "modules": c.Locals("userModules"), } if err := c.Render("saas_dispatch_logs", data, "layouts/main"); err != nil { return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": err.Error()}) } return nil } // GetSaasDispatchLogs devuelve los logs de despacho paginados. func GetSaasDispatchLogs(c *fiber.Ctx) error { page, _ := strconv.Atoi(c.Query("page", "1")) if page < 1 { page = 1 } limit := 30 offset := (page - 1) * limit items, total, err := models.GetSaasDispatchLogs(limit, offset) if err != nil { return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": err.Error()}) } return c.JSON(fiber.Map{ "items": items, "total": total, "totalPages": int(math.Ceil(float64(total) / float64(limit))), "page": page, "limit": limit, }) }