package controllers import ( "strings" "github.com/gofiber/fiber/v2" "github.com/sujit-baniya/fiber-boilerplate/pkg/models" "github.com/sujit-baniya/fiber-boilerplate/pkg/services" ) // ─── Vistas ────────────────────────────────────────────────────────────────── func WebSmsConfigPage(c *fiber.Ctx) error { cfg, _ := models.GetWebSmsConfig() return c.Render("websms_config", fiber.Map{ "user": c.Locals("user"), "modules": c.Locals("userModules"), "cfg": cfg, }, "layouts/main") } // ─── API ───────────────────────────────────────────────────────────────────── func GetWebSmsConfig(c *fiber.Ctx) error { cfg, err := models.GetWebSmsConfig() if err != nil { return c.JSON(fiber.Map{"data": nil}) } return c.JSON(fiber.Map{"data": cfg}) } func SaveWebSmsConfig(c *fiber.Ctx) error { type body struct { ID uint `json:"id"` Username string `json:"username"` ApiToken string `json:"api_token"` Sender string `json:"sender"` Notas string `json:"notas"` } var b body if err := c.BodyParser(&b); err != nil { return c.Status(400).JSON(fiber.Map{"error": "body inválido"}) } if b.Username == "" { return c.Status(400).JSON(fiber.Map{"error": "username es requerido"}) } if b.ApiToken == "" { return c.Status(400).JSON(fiber.Map{"error": "api_token es requerido"}) } cfg := models.WebSmsConfig{ Username: b.Username, ApiToken: b.ApiToken, Sender: b.Sender, Notas: b.Notas, } cfg.ID = b.ID if err := models.SaveWebSmsConfig(cfg); err != nil { return c.Status(500).JSON(fiber.Map{"error": err.Error()}) } return c.JSON(fiber.Map{"message": "Configuración WebSMS guardada"}) } func TestWebSms(c *fiber.Ctx) error { type body struct { Para string `json:"para"` Mensaje string `json:"mensaje"` } var b body if err := c.BodyParser(&b); err != nil { return c.Status(400).JSON(fiber.Map{"error": "body inválido"}) } if b.Para == "" { return c.Status(400).JSON(fiber.Map{"error": "número de destino requerido"}) } if b.Mensaje == "" { b.Mensaje = "[TEST] Notificación desde U-site vía WebSMS" } cfg, err := models.GetWebSmsConfig() if err != nil { return c.Status(400).JSON(fiber.Map{"error": "WebSMS no configurado"}) } resp, err := services.SendWebSms(cfg, b.Para, b.Mensaje) if err != nil { return c.Status(500).JSON(fiber.Map{"error": err.Error()}) } models.CreateWebSmsLog(&models.WebSmsLog{ Para: b.Para, Mensaje: b.Mensaje, Status: resp.Code, MsgID: resp.MsgID(), }) return c.JSON(fiber.Map{"ok": true, "response": resp}) } func GetWebSmsLogs(c *fiber.Ctx) error { logs, err := models.GetWebSmsLogs(50) if err != nil { return c.Status(500).JSON(fiber.Map{"error": err.Error()}) } return c.JSON(logs) } func GetWebSmsWebhookLogs(c *fiber.Ctx) error { logs, err := models.GetWebSmsWebhookLogs(50) if err != nil { return c.Status(500).JSON(fiber.Map{"error": err.Error()}) } return c.JSON(logs) } // ─── Webhooks entrantes ───────────────────────────────────────────────────── func WebSmsDeliveryWebhook(c *fiber.Ctx) error { var payload services.WebSmsAckPayload if err := c.BodyParser(&payload); err != nil { return c.Status(400).JSON(fiber.Map{"error": "body inválido"}) } raw := c.Body() models.CreateWebSmsWebhookLog(&models.WebSmsWebhookLog{ Tipo: "delivery", MsgID: payload.ID, Para: payload.Msisdn, Status: payload.Status, Raw: string(raw), }) return c.SendStatus(200) } func WebSmsClickWebhook(c *fiber.Ctx) error { var payload services.WebSmsClickPayload if err := c.BodyParser(&payload); err != nil { return c.Status(400).JSON(fiber.Map{"error": "body inválido"}) } raw := c.Body() models.CreateWebSmsWebhookLog(&models.WebSmsWebhookLog{ Tipo: "click", MsgID: payload.ID, Para: payload.Msisdn, Status: "clicked", Raw: string(raw), }) return c.SendStatus(200) } // ─── API pública ──────────────────────────────────────────────────────────── // ApiSendSms envía un SMS. Requiere Authorization: Bearer . // POST /api/sms/send { "numero": "573001234567", "mensaje": "Hola" } func ApiSendSms(c *fiber.Ctx) error { bearer := strings.TrimPrefix(c.Get("Authorization"), "Bearer ") if bearer == "" { return c.Status(401).JSON(fiber.Map{"error": "token requerido"}) } cfg, err := models.GetWebSmsConfig() if err != nil { return c.Status(503).JSON(fiber.Map{"error": "WebSMS no configurado"}) } if cfg.SecretKey == "" || cfg.SecretKey != bearer { return c.Status(401).JSON(fiber.Map{"error": "token inválido"}) } type body struct { Numero string `json:"numero"` Mensaje string `json:"mensaje"` } var b body if err := c.BodyParser(&b); err != nil || b.Numero == "" || b.Mensaje == "" { return c.Status(400).JSON(fiber.Map{"error": "numero y mensaje son requeridos"}) } resp, err := services.SendWebSms(cfg, b.Numero, b.Mensaje) errStr := "" status := "ok" if err != nil { errStr = err.Error() status = "error" } else if resp != nil { status = resp.Code } models.CreateWebSmsLog(&models.WebSmsLog{ Para: b.Numero, Mensaje: b.Mensaje, Status: status, MsgID: func() string { if resp != nil { return resp.MsgID() }; return "" }(), Error: errStr, }) if err != nil { return c.Status(500).JSON(fiber.Map{"error": errStr}) } return c.JSON(fiber.Map{"ok": true, "id": resp.MsgID()}) } func WebSmsIncomingWebhook(c *fiber.Ctx) error { var payload services.WebSmsIncomingPayload if err := c.BodyParser(&payload); err != nil { return c.Status(400).JSON(fiber.Map{"error": "body inválido"}) } raw := c.Body() models.CreateWebSmsWebhookLog(&models.WebSmsWebhookLog{ Tipo: "incoming", MsgID: payload.ID, Para: payload.Msisdn, Status: "received", Raw: string(raw), }) return c.SendStatus(200) }