package controllers import ( "math" "strconv" "strings" "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" ) func PortalUsuariosIndex(c *fiber.Ctx) error { return c.Render("portal_usuarios", fiber.Map{ "user": c.Locals("user"), "modules": c.Locals("userModules"), }, "layouts/main") } func LoadPortalUsuarios(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.GetAllPortalUsers(limit, offset) if err != nil { return c.Status(500).JSON(fiber.Map{"error": err.Error()}) } clientes, _, _ := models.GetAllClientes(200, 0, "") portalRoles, _ := models.GetPortalRoles() return c.JSON(fiber.Map{ "items": items, "total": total, "totalPages": int(math.Ceil(float64(total) / float64(limit))), "page": page, "clientes": clientes, "portalRoles": portalRoles, }) } func CreatePortalUsuario(c *fiber.Ctx) error { type Req struct { Nombre string `json:"nombre"` Email string `json:"email"` Password string `json:"password"` ClienteID *uint `json:"cliente_id"` RoleID *uint `json:"role_id"` Rol string `json:"rol"` Notas string `json:"notas"` TelegramChatID string `json:"telegram_chat_id"` SitioWeb string `json:"sitio_web"` Telefono string `json:"telefono"` Indicativo string `json:"indicativo"` Pais string `json:"pais"` Ciudad string `json:"ciudad"` } var req Req if err := c.BodyParser(&req); err != nil { return c.Status(400).JSON(fiber.Map{"error": err.Error()}) } if strings.TrimSpace(req.Nombre) == "" || strings.TrimSpace(req.Email) == "" || strings.TrimSpace(req.Password) == "" { return c.Status(400).JSON(fiber.Map{"error": "nombre, email y password son requeridos"}) } hashed, err := app.Http.Hash.Create(req.Password) if err != nil { return c.Status(500).JSON(fiber.Map{"error": "Error al hashear contraseña"}) } if req.Rol == "" { req.Rol = "cliente" } // Derivar Rol del tipo de rol seleccionado rol := req.Rol if req.RoleID != nil { var role models.Roles if err := app.Http.Database.DB.First(&role, *req.RoleID).Error; err == nil { if role.EsPortalPartner { rol = "partner" } } } u := &models.PortalUser{ Nombre: req.Nombre, Email: strings.ToLower(strings.TrimSpace(req.Email)), Password: hashed, ClienteID: req.ClienteID, RoleID: req.RoleID, Rol: rol, Activo: true, Notas: req.Notas, TelegramChatID: req.TelegramChatID, SitioWeb: req.SitioWeb, Telefono: req.Telefono, Indicativo: req.Indicativo, Pais: req.Pais, Ciudad: req.Ciudad, } if err := models.CreatePortalUser(u); err != nil { return c.Status(500).JSON(fiber.Map{"error": err.Error()}) } u.Password = "" return c.Status(201).JSON(u) } func UpdatePortalUsuario(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"}) } type Req struct { Nombre string `json:"nombre"` Email string `json:"email"` Password string `json:"password"` ClienteID *uint `json:"cliente_id"` RoleID *uint `json:"role_id"` Rol string `json:"rol"` Activo bool `json:"activo"` Notas string `json:"notas"` TelegramChatID string `json:"telegram_chat_id"` SitioWeb string `json:"sitio_web"` Telefono string `json:"telefono"` Indicativo string `json:"indicativo"` Pais string `json:"pais"` Ciudad string `json:"ciudad"` } var req Req if err := c.BodyParser(&req); err != nil { return c.Status(400).JSON(fiber.Map{"error": err.Error()}) } // Derivar Rol del tipo de rol seleccionado rol := req.Rol if req.RoleID != nil { var role models.Roles if err := app.Http.Database.DB.First(&role, *req.RoleID).Error; err == nil { if role.EsPortalPartner { rol = "partner" } } } u := &models.PortalUser{ Nombre: req.Nombre, Email: strings.ToLower(strings.TrimSpace(req.Email)), ClienteID: req.ClienteID, RoleID: req.RoleID, Rol: rol, Activo: req.Activo, Notas: req.Notas, TelegramChatID: req.TelegramChatID, SitioWeb: req.SitioWeb, Telefono: req.Telefono, Indicativo: req.Indicativo, Pais: req.Pais, Ciudad: req.Ciudad, } u.ID = uint(id) if err := models.UpdatePortalUser(u); err != nil { return c.Status(500).JSON(fiber.Map{"error": err.Error()}) } // Actualizar password solo si se envió if strings.TrimSpace(req.Password) != "" { hashed, err := app.Http.Hash.Create(req.Password) if err == nil { _ = models.UpdatePortalUserPassword(uint(id), hashed) } } return c.JSON(fiber.Map{"ok": true}) } func DeletePortalUsuario(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.DeletePortalUser(uint(id)); err != nil { return c.Status(500).JSON(fiber.Map{"error": err.Error()}) } return c.JSON(fiber.Map{"ok": true}) } func AddPortalAcceso(c *fiber.Ctx) error { id, _ := strconv.ParseUint(c.Params("id"), 10, 32) type Req struct { ClienteID uint `json:"cliente_id"` } var req Req if err := c.BodyParser(&req); err != nil { return c.Status(400).JSON(fiber.Map{"error": err.Error()}) } if err := models.AddPortalAcceso(uint(id), req.ClienteID); err != nil { return c.Status(500).JSON(fiber.Map{"error": err.Error()}) } return c.JSON(fiber.Map{"ok": true}) } func RemovePortalAcceso(c *fiber.Ctx) error { id, _ := strconv.ParseUint(c.Params("id"), 10, 32) clienteID, _ := strconv.ParseUint(c.Params("clienteID"), 10, 32) if err := models.RemovePortalAcceso(uint(id), uint(clienteID)); err != nil { return c.Status(500).JSON(fiber.Map{"error": err.Error()}) } return c.JSON(fiber.Map{"ok": true}) } // SendPortalCredentials envía las credenciales de acceso al portal al correo del usuario. func SendPortalCredentials(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"}) } u, err := models.GetPortalUserByID(uint(id)) if err != nil { return c.Status(404).JSON(fiber.Map{"error": "Usuario no encontrado"}) } type Req struct { Password string `json:"password"` } var req Req _ = c.BodyParser(&req) password := req.Password if password == "" { password = "(la contraseña que configuraste)" } services.SendPortalCredentialsEmail(u.Email, u.Nombre, password) return c.JSON(fiber.Map{"ok": true, "message": "Correo enviado a " + u.Email}) } // GetPortalUsuarioDetail devuelve todos los campos de un portal_user para el panel de detalle. func GetPortalUsuarioDetail(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"}) } u, err := models.GetPortalUserByID(uint(id)) if err != nil { return c.Status(404).JSON(fiber.Map{"error": "Usuario no encontrado"}) } return c.JSON(u) } // PortalUsuarioRutFile sirve el archivo RUT/documento del portal user al admin. func PortalUsuarioRutFile(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"}) } u, err := models.GetPortalUserByID(uint(id)) if err != nil { return c.Status(404).JSON(fiber.Map{"error": "Usuario no encontrado"}) } if u.DocumentoRutFile == "" { return c.Status(404).JSON(fiber.Map{"error": "Este usuario no tiene archivo RUT"}) } return c.SendFile(u.DocumentoRutFile) }