From fcc3ff7ca74b1d31c5aec4f850cf2244f6ebf4af Mon Sep 17 00:00:00 2001 From: Lizandro Guarnizo <77708265+lizandrogd@users.noreply.github.com> Date: Sat, 16 May 2026 21:05:05 -0500 Subject: [PATCH] up --- pkg/models/portal_user.go | 6 + resources/views/layouts/portal.html | 221 ++++++++++++++++++++++++++ rest/controllers/portal_controller.go | 115 ++++++++++++++ rest/routes/portal.go | 5 + 4 files changed, 347 insertions(+) diff --git a/pkg/models/portal_user.go b/pkg/models/portal_user.go index 80fac50..b641690 100644 --- a/pkg/models/portal_user.go +++ b/pkg/models/portal_user.go @@ -26,7 +26,10 @@ type PortalUser struct { Notas string `json:"notas" gorm:"column:notas;type:text"` TelegramChatID string `json:"telegram_chat_id" gorm:"column:telegram_chat_id"` Telefono string `json:"telefono" gorm:"column:telefono"` + Indicativo string `json:"indicativo" gorm:"column:indicativo"` // ej: +57, +1 Pais string `json:"pais" gorm:"column:pais"` + Documento string `json:"documento" gorm:"column:documento"` // RUT, NIT, CC, etc. + Empresa string `json:"empresa" gorm:"column:empresa"` // empresa que representa PortalAccesos []PortalAcceso `json:"portal_accesos" gorm:"foreignKey:PortalUserID"` } @@ -85,7 +88,10 @@ func UpdatePortalUser(u *PortalUser) error { "notas": u.Notas, "telegram_chat_id": u.TelegramChatID, "telefono": u.Telefono, + "indicativo": u.Indicativo, "pais": u.Pais, + "documento": u.Documento, + "empresa": u.Empresa, }).Error } diff --git a/resources/views/layouts/portal.html b/resources/views/layouts/portal.html index ca0a426..77e9614 100644 --- a/resources/views/layouts/portal.html +++ b/resources/views/layouts/portal.html @@ -101,6 +101,174 @@ + +
+ + + +
+ +
+ +
+ + +
+

Mi cuenta

+ +
+ + +
+ + +
+ + +
+ + +
+

+ +
+ + +
+ +
+ + +
+ +
+ +
+ + +
+
+ +
+ + +
+ +
+ + +

Documento legal de tu país (NIT, RUT, Cédula, CUIT, RFC, etc.)

+
+ +
+ + +
+
+ + +
+

+ +
+ + +
+ +
+ + +
+ +
+ + +
+
+ +
+ + +
+ + +
+ +
+
+
+ Cerrar sesión @@ -118,5 +286,58 @@ Powered by U-site — © 2025 + + diff --git a/rest/controllers/portal_controller.go b/rest/controllers/portal_controller.go index 4fdbea7..b3ba073 100644 --- a/rest/controllers/portal_controller.go +++ b/rest/controllers/portal_controller.go @@ -6,6 +6,7 @@ import ( "strings" "github.com/gofiber/fiber/v2" + "github.com/sujit-baniya/fiber-boilerplate/app" "github.com/sujit-baniya/fiber-boilerplate/pkg/auth" "github.com/sujit-baniya/fiber-boilerplate/pkg/models" "github.com/sujit-baniya/fiber-boilerplate/pkg/services" @@ -391,3 +392,117 @@ func PortalMarcarTicketLeido(c *fiber.Ctx) error { _ = models.MarkTicketMessagesReadByPortal(uint(ticketID)) return c.JSON(fiber.Map{"ok": true}) } + +// ─── Mi Perfil ──────────────────────────────────────────────────────────────── + +// GET /portal/mi-perfil — devuelve datos del usuario autenticado +func PortalGetMiPerfil(c *fiber.Ctx) error { + u := middlewares.PortalUserFromLocals(c) + if u == nil { + return c.Status(401).JSON(fiber.Map{"error": "no autenticado"}) + } + full, err := models.GetPortalUserByID(u.ID) + if err != nil { + return c.Status(500).JSON(fiber.Map{"error": "error al obtener perfil"}) + } + return c.JSON(fiber.Map{ + "id": full.ID, + "nombre": full.Nombre, + "email": full.Email, + "telefono": full.Telefono, + "indicativo": full.Indicativo, + "pais": full.Pais, + "documento": full.Documento, + "empresa": full.Empresa, + }) +} + +// PUT /portal/mi-perfil — actualiza datos del usuario autenticado +func PortalUpdateMiPerfil(c *fiber.Ctx) error { + u := middlewares.PortalUserFromLocals(c) + if u == nil { + return c.Status(401).JSON(fiber.Map{"error": "no autenticado"}) + } + type Req struct { + Nombre string `json:"nombre"` + Email string `json:"email"` + Telefono string `json:"telefono"` + Indicativo string `json:"indicativo"` + Pais string `json:"pais"` + Documento string `json:"documento"` + Empresa string `json:"empresa"` + } + var req Req + if err := c.BodyParser(&req); err != nil { + return c.Status(400).JSON(fiber.Map{"error": "Datos inválidos"}) + } + req.Nombre = strings.TrimSpace(req.Nombre) + req.Email = strings.TrimSpace(req.Email) + if req.Nombre == "" { + return c.Status(400).JSON(fiber.Map{"error": "El nombre es requerido"}) + } + if req.Email == "" { + return c.Status(400).JSON(fiber.Map{"error": "El email es requerido"}) + } + // Verificar que el email no lo use otro usuario + existing, err := models.GetPortalUserByEmail(req.Email) + if err == nil && existing.ID != u.ID { + return c.Status(400).JSON(fiber.Map{"error": "El email ya está en uso"}) + } + full, err := models.GetPortalUserByID(u.ID) + if err != nil { + return c.Status(500).JSON(fiber.Map{"error": "Usuario no encontrado"}) + } + full.Nombre = req.Nombre + full.Email = req.Email + full.Telefono = req.Telefono + full.Indicativo = req.Indicativo + full.Pais = req.Pais + full.Documento = req.Documento + full.Empresa = req.Empresa + if err := models.UpdatePortalUser(full); err != nil { + return c.Status(500).JSON(fiber.Map{"error": err.Error()}) + } + return c.JSON(fiber.Map{"ok": true}) +} + +// PUT /portal/mi-perfil/password — cambia la contraseña del usuario autenticado +func PortalCambiarPassword(c *fiber.Ctx) error { + u := middlewares.PortalUserFromLocals(c) + if u == nil { + return c.Status(401).JSON(fiber.Map{"error": "no autenticado"}) + } + type Req struct { + Actual string `json:"actual"` + Nueva string `json:"nueva"` + Confirma string `json:"confirma"` + } + var req Req + if err := c.BodyParser(&req); err != nil { + return c.Status(400).JSON(fiber.Map{"error": "Datos inválidos"}) + } + if strings.TrimSpace(req.Nueva) == "" { + return c.Status(400).JSON(fiber.Map{"error": "La nueva contraseña no puede estar vacía"}) + } + if req.Nueva != req.Confirma { + return c.Status(400).JSON(fiber.Map{"error": "Las contraseñas no coinciden"}) + } + if len(req.Nueva) < 8 { + return c.Status(400).JSON(fiber.Map{"error": "La contraseña debe tener al menos 8 caracteres"}) + } + full, err := models.GetPortalUserByID(u.ID) + if err != nil { + return c.Status(500).JSON(fiber.Map{"error": "Usuario no encontrado"}) + } + if match, matchErr := app.Http.Hash.Match(req.Actual, full.Password); matchErr != nil || !match { + return c.Status(400).JSON(fiber.Map{"error": "La contraseña actual es incorrecta"}) + } + hashed, err := app.Http.Hash.Create(req.Nueva) + if err != nil { + return c.Status(500).JSON(fiber.Map{"error": "Error al procesar contraseña"}) + } + if err := models.UpdatePortalUserPassword(u.ID, hashed); err != nil { + return c.Status(500).JSON(fiber.Map{"error": err.Error()}) + } + return c.JSON(fiber.Map{"ok": true}) +} diff --git a/rest/routes/portal.go b/rest/routes/portal.go index 7c7fe9f..bc48b70 100644 --- a/rest/routes/portal.go +++ b/rest/routes/portal.go @@ -40,4 +40,9 @@ func PortalRoutes(app fiber.Router) { portal.Get("/partner-recursos", middlewares.PortalPartnerOnly(), controllers.PortalPartnerRecursos) portal.Get("/partner-recursos/:id/download", middlewares.PortalPartnerOnly(), controllers.PortalDownloadPartnerRecurso) portal.Get("/partner-comunicados/:id/download", middlewares.PortalPartnerOnly(), controllers.DownloadPartnerComunicadoArchivo) + + // Mi perfil + portal.Get("/mi-perfil", controllers.PortalGetMiPerfil) + portal.Put("/mi-perfil", controllers.PortalUpdateMiPerfil) + portal.Put("/mi-perfil/password", controllers.PortalCambiarPassword) }