diff --git a/config.sample.yml b/config.sample.yml index 795f919..6e13018 100755 --- a/config.sample.yml +++ b/config.sample.yml @@ -48,14 +48,14 @@ mail: token: app_jwt_secret: SECRET_APP api_jwt_secret: SECRET_API - expires_in: 3600 + expires_in: 31536000 jwt: app: secret: SECRET_APP - expire: 3600 + expire: 31536000 api: secret: SECRET_API - expire: 3600 + expire: 31536000 template: path: "resources/view" diff --git a/config.yml b/config.yml index c88fe47..cc1dce0 100755 --- a/config.yml +++ b/config.yml @@ -53,14 +53,14 @@ mail: token: app_jwt_secret: SECRET_APP api_jwt_secret: SECRET_API - expires_in: 3600 + expires_in: 31536000 jwt: app: secret: SECRET_APP - expire: 3600 + expire: 31536000 api: secret: SECRET_API - expire: 3600 + expire: 31536000 template: path: "resources/view" diff --git a/config/session.go b/config/session.go index 6ba72ad..3dd46ea 100755 --- a/config/session.go +++ b/config/session.go @@ -28,7 +28,9 @@ func (s *SessionConfig) Setup() error { } // Configurar el proveedor de sesiones en memoria - store := session.New() // Usar el proveedor de sesiones en memoria + store := session.New(session.Config{ + Expiration: 365 * 24 * time.Hour, // 1 año + }) // Usar el proveedor de sesiones en memoria // Crear una nueva sesión s.Session = store diff --git a/config/token.go b/config/token.go index f8d59a9..53c4076 100755 --- a/config/token.go +++ b/config/token.go @@ -24,7 +24,7 @@ func (t *Token) CreateToken(c *fiber.Ctx, userID uint, secret string, expire ... if len(expire) > 0 { t.Expire = expire[0] } else { - t.Expire = 3600 + t.Expire = 31536000 // 1 año por defecto si no se configura } expiresIn := time.Now().Add(time.Duration(t.Expire) * time.Second).Unix() claims["exp"] = expiresIn diff --git a/resources/views/renovaciones/plantillas.html b/resources/views/renovaciones/plantillas.html index 1c80cc0..c7bf830 100644 --- a/resources/views/renovaciones/plantillas.html +++ b/resources/views/renovaciones/plantillas.html @@ -110,7 +110,9 @@ +

@@ -177,7 +179,7 @@ document.addEventListener('alpine:init', () => { loading: false, datos: [], total: 0, totalPages: 1, page: 1, limit: 10, search: '', addModal: false, editModal: false, deleteModal: false, previewModal: false, testModal: false, - selectedId: null, testEmail: '', + selectedId: null, testEmail: '', templateError: '', form: { nombre:'', asunto:'', cuerpo_html:'', tipo:'renovacion' }, toast: { show:false, msg:'', type:'ok' }, @@ -211,18 +213,25 @@ document.addEventListener('alpine:init', () => { }); }, - previewInline() { + async previewInline() { const frame = this.$refs.previewFrame; if (frame) frame.srcdoc = this.form.cuerpo_html || '

Sin contenido

'; + if (!this.form.cuerpo_html) { this.templateError = ''; return; } + try { + const { data } = await axios.post('/app/api/plantillas-correo/validate', { html: this.form.cuerpo_html }); + this.templateError = data.ok ? '' : (data.error || 'Sintaxis inválida'); + } catch { this.templateError = ''; } }, closeModals() { this.addModal = this.editModal = this.deleteModal = this.previewModal = this.testModal = false; this.selectedId = null; + this.templateError = ''; this.form = { nombre:'', asunto:'', cuerpo_html:'', tipo:'renovacion' }; }, async save() { + if (this.templateError) { this.showToast('Corrige los errores de sintaxis antes de guardar', 'error'); return; } this.loading = true; try { if (this.editModal) { diff --git a/rest/controllers/notificacion_controller.go b/rest/controllers/notificacion_controller.go index 825aa0c..6491208 100644 --- a/rest/controllers/notificacion_controller.go +++ b/rest/controllers/notificacion_controller.go @@ -4,6 +4,7 @@ import ( "html/template" "math" "strconv" + "strings" "github.com/gofiber/fiber/v2" "github.com/sujit-baniya/fiber-boilerplate/pkg/models" @@ -101,6 +102,24 @@ func PreviewPlantilla(c *fiber.Ctx) 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 { diff --git a/rest/routes/renovaciones.go b/rest/routes/renovaciones.go index d4df8dd..ae3f347 100644 --- a/rest/routes/renovaciones.go +++ b/rest/routes/renovaciones.go @@ -42,6 +42,7 @@ func RenovacionesRoutes(protected fiber.Router) { protected.Delete("/api/plantillas-correo/:id", controllers.DeletePlantilla) protected.Get("/api/plantillas-correo/:id/preview", controllers.PreviewPlantilla) protected.Post("/api/plantillas-correo/:id/test", controllers.TestEnvioPlantilla) + protected.Post("/api/plantillas-correo/validate", controllers.ValidarPlantilla) // ─── Reglas de notificación ─────────────────────────────────────── protected.Get("/reglas-notificacion", middlewares.MenuMiddleware, controllers.ReglasView)