package controllers import ( "math" "strconv" "strings" "text/template" "github.com/gofiber/fiber/v2" "github.com/sujit-baniya/fiber-boilerplate/app" "github.com/sujit-baniya/fiber-boilerplate/pkg/models" "github.com/sujit-baniya/fiber-boilerplate/pkg/services" "github.com/sujit-baniya/fiber-boilerplate/utils" ) // ─── Plantillas ───────────────────────────────────────────────────────────── func PlantillasView(c *fiber.Ctx) error { return c.Render("renovaciones/plantillas", fiber.Map{ "user": c.Locals("user"), "modules": c.Locals("userModules"), }, "layouts/main") } func GetPlantillas(c *fiber.Ctx) error { page, _ := strconv.Atoi(c.Query("page", "1")) limit, _ := strconv.Atoi(c.Query("limit", "10")) if page < 1 { page = 1 } offset := (page - 1) * limit records, total, err := models.GetAllPlantillas(limit, offset, c.Query("search")) if err != nil { return c.Status(500).JSON(fiber.Map{"error": err.Error()}) } return c.JSON(fiber.Map{ "registros": records, "total": total, "totalPages": int(math.Ceil(float64(total) / float64(limit))), "page": page, }) } func CreatePlantilla(c *fiber.Ctx) error { var m models.PlantillaCorreo if err := c.BodyParser(&m); err != nil { return c.Status(400).JSON(fiber.Map{"error": err.Error()}) } if m.CuerpoHTML != "" { if _, err := template.New("validate").Parse(m.CuerpoHTML); err != nil { return c.Status(400).JSON(fiber.Map{"error": "Sintaxis inválida en el HTML: " + err.Error()}) } } if err := models.CreatePlantilla(m); err != nil { return c.Status(500).JSON(fiber.Map{"error": err.Error()}) } return c.Status(201).JSON(fiber.Map{"message": "Plantilla creada", "ok": true}) } func UpdatePlantilla(c *fiber.Ctx) error { id, err := strconv.ParseUint(c.Params("id"), 10, 32) if err != nil { return c.Status(400).JSON(fiber.Map{"error": "ID inválido"}) } var updates map[string]interface{} if err := c.BodyParser(&updates); err != nil { return c.Status(400).JSON(fiber.Map{"error": err.Error()}) } if html, ok := updates["cuerpo_html"].(string); ok && html != "" { if _, err := template.New("validate").Parse(html); err != nil { return c.Status(400).JSON(fiber.Map{"error": "Sintaxis inválida en el HTML: " + err.Error()}) } } if err := models.UpdatePlantilla(uint(id), updates); err != nil { return c.Status(500).JSON(fiber.Map{"error": err.Error()}) } return c.JSON(fiber.Map{"message": "Actualizado", "ok": true}) } func DeletePlantilla(c *fiber.Ctx) error { id, err := strconv.ParseUint(c.Params("id"), 10, 32) if err != nil { return c.Status(400).JSON(fiber.Map{"error": "ID inválido"}) } if err := models.DeletePlantilla(uint(id)); err != nil { return c.Status(500).JSON(fiber.Map{"error": err.Error()}) } return c.JSON(fiber.Map{"message": "Eliminado", "ok": true}) } func PreviewPlantilla(c *fiber.Ctx) error { id, err := strconv.ParseUint(c.Params("id"), 10, 32) if err != nil { return c.Status(400).JSON(fiber.Map{"error": "ID inválido"}) } p, err := models.GetPlantillaByID(uint(id)) if err != nil { return c.Status(404).JSON(fiber.Map{"error": "No encontrada"}) } html, err := services.RenderPlantilla(p, services.DatosEjemplo()) if err != nil { return c.Status(500).JSON(fiber.Map{"error": err.Error()}) } return c.JSON(fiber.Map{"html": html, "ok": true}) } // ValidarPlantilla comprueba si el CuerpoHTML es un Go template válido func ValidarPlantilla(c *fiber.Ctx) error { var body struct { HTML string `json:"html"` } if err := c.BodyParser(&body); err != nil { return c.Status(400).JSON(fiber.Map{"error": err.Error()}) } html := strings.TrimSpace(body.HTML) if html == "" { return c.JSON(fiber.Map{"ok": true}) } if _, err := template.New("validate").Parse(html); err != nil { return c.Status(400).JSON(fiber.Map{"ok": false, "error": err.Error()}) } return c.JSON(fiber.Map{"ok": true}) } func TestEnvioPlantilla(c *fiber.Ctx) error { id, err := strconv.ParseUint(c.Params("id"), 10, 32) if err != nil { return c.Status(400).JSON(fiber.Map{"error": "ID inválido"}) } var body struct { Email string `json:"email"` } if err := c.BodyParser(&body); err != nil || body.Email == "" { return c.Status(400).JSON(fiber.Map{"error": "Email requerido"}) } p, err := models.GetPlantillaByID(uint(id)) if err != nil { return c.Status(404).JSON(fiber.Map{"error": "No encontrada"}) } // Recargar siempre la config activa desde BD antes de enviar if cfg, err2 := models.GetSmtpConfig(); err2 == nil { app.Http.Mail.Host = cfg.Host app.Http.Mail.Port = cfg.Port app.Http.Mail.Username = cfg.Username app.Http.Mail.Password = utils.Decrypt(cfg.Password, app.Http.Server.Key) app.Http.Mail.Encryption = cfg.Encryption app.Http.Mail.FromAddress = cfg.FromAddress app.Http.Mail.FromName = cfg.FromName app.Http.Mail.SetupMailer() } if err := services.EnviarCorreoPrueba(body.Email, p); err != nil { return c.Status(500).JSON(fiber.Map{"error": err.Error()}) } return c.JSON(fiber.Map{"message": "Correo enviado", "ok": true}) } // ─── Reglas ────────────────────────────────────────────────────────────────── func ReglasView(c *fiber.Ctx) error { return c.Render("renovaciones/reglas", fiber.Map{ "user": c.Locals("user"), "modules": c.Locals("userModules"), }, "layouts/main") } func GetReglas(c *fiber.Ctx) error { records, err := models.GetAllReglas() if err != nil { return c.Status(500).JSON(fiber.Map{"error": err.Error()}) } return c.JSON(fiber.Map{"registros": records, "total": len(records)}) } func CreateRegla(c *fiber.Ctx) error { var m models.NotificacionRegla if err := c.BodyParser(&m); err != nil { return c.Status(400).JSON(fiber.Map{"error": err.Error()}) } if err := models.CreateRegla(m); err != nil { return c.Status(500).JSON(fiber.Map{"error": err.Error()}) } return c.Status(201).JSON(fiber.Map{"message": "Regla creada", "ok": true}) } func UpdateRegla(c *fiber.Ctx) error { id, err := strconv.ParseUint(c.Params("id"), 10, 32) if err != nil { return c.Status(400).JSON(fiber.Map{"error": "ID inválido"}) } var m models.NotificacionRegla if err := c.BodyParser(&m); err != nil { return c.Status(400).JSON(fiber.Map{"error": err.Error()}) } m.ID = uint(id) if err := models.UpdateRegla(m); err != nil { return c.Status(500).JSON(fiber.Map{"error": err.Error()}) } return c.JSON(fiber.Map{"message": "Actualizado", "ok": true}) } func DeleteRegla(c *fiber.Ctx) error { id, err := strconv.ParseUint(c.Params("id"), 10, 32) if err != nil { return c.Status(400).JSON(fiber.Map{"error": "ID inválido"}) } if err := models.DeleteRegla(uint(id)); err != nil { return c.Status(500).JSON(fiber.Map{"error": err.Error()}) } return c.JSON(fiber.Map{"message": "Eliminado", "ok": true}) } // ─── Historial ─────────────────────────────────────────────────────────────── func HistorialView(c *fiber.Ctx) error { return c.Render("renovaciones/historial", fiber.Map{ "user": c.Locals("user"), "modules": c.Locals("userModules"), }, "layouts/main") } func GetHistorial(c *fiber.Ctx) error { page, _ := strconv.Atoi(c.Query("page", "1")) limit, _ := strconv.Atoi(c.Query("limit", "20")) if page < 1 { page = 1 } offset := (page - 1) * limit records, total, err := models.GetAllLogs(limit, offset) if err != nil { return c.Status(500).JSON(fiber.Map{"error": err.Error()}) } return c.JSON(fiber.Map{ "registros": records, "total": total, "totalPages": int(math.Ceil(float64(total) / float64(limit))), "page": page, }) } func ReenviarNotificacion(c *fiber.Ctx) error { id, err := strconv.ParseUint(c.Params("id"), 10, 32) if err != nil { return c.Status(400).JSON(fiber.Map{"error": "ID inválido"}) } log, err := models.GetLogByID(uint(id)) if err != nil { return c.Status(404).JSON(fiber.Map{"error": "No encontrado"}) } if err := services.ReenviarLog(log); err != nil { return c.Status(500).JSON(fiber.Map{"error": err.Error()}) } return c.JSON(fiber.Map{"message": "Reenviado", "ok": true}) } func VerPreviewLog(c *fiber.Ctx) error { id, err := strconv.ParseUint(c.Params("id"), 10, 32) if err != nil { return c.Status(400).JSON(fiber.Map{"error": "ID inválido"}) } log, err := models.GetLogByID(uint(id)) if err != nil { return c.Status(404).JSON(fiber.Map{"error": "No encontrado"}) } return c.JSON(fiber.Map{"html": log.PreviewHTML, "asunto": log.Asunto, "ok": true}) }