up
This commit is contained in:
@@ -3,6 +3,8 @@ package controllers
|
||||
import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
@@ -406,14 +408,16 @@ func PortalGetMiPerfil(c *fiber.Ctx) error {
|
||||
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,
|
||||
"id": full.ID,
|
||||
"nombre": full.Nombre,
|
||||
"email": full.Email,
|
||||
"telefono": full.Telefono,
|
||||
"indicativo": full.Indicativo,
|
||||
"pais": full.Pais,
|
||||
"documento": full.Documento,
|
||||
"empresa": full.Empresa,
|
||||
"documento_rut_file": full.DocumentoRutFile,
|
||||
"documento_rut_nombre": full.DocumentoRutNombre,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -506,3 +510,147 @@ func PortalCambiarPassword(c *fiber.Ctx) error {
|
||||
}
|
||||
return c.JSON(fiber.Map{"ok": true})
|
||||
}
|
||||
|
||||
// POST /portal/mi-perfil/rut-file — sube el documento RUT del usuario autenticado
|
||||
func PortalSubirRutDocumento(c *fiber.Ctx) error {
|
||||
u := middlewares.PortalUserFromLocals(c)
|
||||
if u == nil {
|
||||
return c.Status(401).JSON(fiber.Map{"error": "no autenticado"})
|
||||
}
|
||||
file, err := c.FormFile("rut_file")
|
||||
if err != nil {
|
||||
return c.Status(400).JSON(fiber.Map{"error": "Archivo requerido"})
|
||||
}
|
||||
if file.Size > 10*1024*1024 {
|
||||
return c.Status(400).JSON(fiber.Map{"error": "Máximo 10 MB"})
|
||||
}
|
||||
ext := strings.ToLower(filepath.Ext(file.Filename))
|
||||
allowed := map[string]bool{".pdf": true, ".jpg": true, ".jpeg": true, ".png": true, ".webp": true}
|
||||
if !allowed[ext] {
|
||||
return c.Status(400).JSON(fiber.Map{"error": "Solo se permiten PDF, JPG, PNG o WEBP"})
|
||||
}
|
||||
dir := fmt.Sprintf("uploads/portal_users/%d", u.ID)
|
||||
if err := os.MkdirAll(dir, 0755); err != nil {
|
||||
return c.Status(500).JSON(fiber.Map{"error": "Error al crear directorio"})
|
||||
}
|
||||
savePath := filepath.Join(dir, "rut"+ext)
|
||||
if err := c.SaveFile(file, savePath); err != nil {
|
||||
return c.Status(500).JSON(fiber.Map{"error": "Error al guardar archivo"})
|
||||
}
|
||||
if err := models.UpdatePortalUserRutFile(u.ID, savePath, file.Filename); err != nil {
|
||||
return c.Status(500).JSON(fiber.Map{"error": err.Error()})
|
||||
}
|
||||
return c.JSON(fiber.Map{"ok": true, "nombre": file.Filename})
|
||||
}
|
||||
|
||||
// ─── Telegram portal ──────────────────────────────────────────────────────────
|
||||
|
||||
// PortalTelegramInit genera un código de vinculación temporal para el usuario del portal.
|
||||
func PortalTelegramInit(c *fiber.Ctx) error {
|
||||
u := middlewares.PortalUserFromLocals(c)
|
||||
if u == nil {
|
||||
return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{"error": "No autenticado"})
|
||||
}
|
||||
token, err := models.GenerateTelegramPortalToken(u.ID)
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "No se pudo generar el código"})
|
||||
}
|
||||
|
||||
// Obtener username del bot desde el primer TelegramConfig activo
|
||||
configs, _ := models.GetAllTelegramConfigs()
|
||||
botToken := ""
|
||||
for _, cfg := range configs {
|
||||
if cfg.Activo && cfg.BotToken != "" {
|
||||
botToken = cfg.BotToken
|
||||
break
|
||||
}
|
||||
}
|
||||
botUsername := services.GetBotUsername(botToken)
|
||||
|
||||
return c.JSON(fiber.Map{
|
||||
"token": token.Token,
|
||||
"bot_username": botUsername,
|
||||
"bot_link": "https://t.me/" + botUsername,
|
||||
})
|
||||
}
|
||||
|
||||
// PortalTelegramStatus devuelve si el usuario del portal tiene Telegram vinculado.
|
||||
func PortalTelegramStatus(c *fiber.Ctx) error {
|
||||
u := middlewares.PortalUserFromLocals(c)
|
||||
if u == nil {
|
||||
return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{"error": "No autenticado"})
|
||||
}
|
||||
full, err := models.GetPortalUserByID(u.ID)
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": err.Error()})
|
||||
}
|
||||
return c.JSON(fiber.Map{
|
||||
"linked": full.TelegramChatID != "",
|
||||
"chat_id": full.TelegramChatID,
|
||||
})
|
||||
}
|
||||
|
||||
// TelegramPortalWebhook recibe actualizaciones del bot de Telegram y vincula el chat_id
|
||||
// al usuario del portal que envió el código de verificación.
|
||||
// Este endpoint debe estar registrado como webhook en el bot: POST /setWebhook?url=.../webhooks/telegram-portal
|
||||
func TelegramPortalWebhook(c *fiber.Ctx) error {
|
||||
var update struct {
|
||||
Message struct {
|
||||
Chat struct {
|
||||
ID int64 `json:"id"`
|
||||
} `json:"chat"`
|
||||
Text string `json:"text"`
|
||||
} `json:"message"`
|
||||
}
|
||||
if err := c.BodyParser(&update); err != nil {
|
||||
return c.SendStatus(fiber.StatusOK)
|
||||
}
|
||||
|
||||
chatID := update.Message.Chat.ID
|
||||
text := strings.TrimSpace(update.Message.Text)
|
||||
if chatID == 0 || text == "" {
|
||||
return c.SendStatus(fiber.StatusOK)
|
||||
}
|
||||
|
||||
// Buscar token en el texto: 6 caracteres hex mayúsculas
|
||||
// Acepta "/vincular A3F9B2" o solo "A3F9B2"
|
||||
var token string
|
||||
for _, part := range strings.Fields(text) {
|
||||
candidate := strings.ToUpper(strings.TrimPrefix(strings.TrimPrefix(part, "/vincular"), "/VINCULAR"))
|
||||
candidate = strings.TrimSpace(candidate)
|
||||
if len(candidate) == 6 {
|
||||
token = candidate
|
||||
break
|
||||
}
|
||||
}
|
||||
if token == "" {
|
||||
return c.SendStatus(fiber.StatusOK)
|
||||
}
|
||||
|
||||
t, err := models.FindTelegramPortalToken(token)
|
||||
if err != nil {
|
||||
portalTelegramReply(chatID, "❌ Código inválido o expirado. Genera un nuevo código desde el portal.")
|
||||
return c.SendStatus(fiber.StatusOK)
|
||||
}
|
||||
|
||||
if err := models.UpdatePortalUserTelegramChatID(t.PortalUserID, fmt.Sprintf("%d", chatID)); err != nil {
|
||||
return c.SendStatus(fiber.StatusOK)
|
||||
}
|
||||
models.DeleteTelegramPortalToken(t.PortalUserID)
|
||||
|
||||
portalTelegramReply(chatID, "✅ ¡Tu Telegram ha sido vinculado al portal correctamente!\n\nRecibirás notificaciones importantes por este medio.")
|
||||
return c.SendStatus(fiber.StatusOK)
|
||||
}
|
||||
|
||||
// portalTelegramReply envía un mensaje usando el primer bot activo configurado.
|
||||
func portalTelegramReply(chatID int64, text string) {
|
||||
configs, _ := models.GetAllTelegramConfigs()
|
||||
for _, cfg := range configs {
|
||||
if cfg.Activo && cfg.BotToken != "" {
|
||||
svc := &services.TelegramService{BotToken: cfg.BotToken}
|
||||
_ = svc.SendMessage(chatID, text)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -208,3 +208,32 @@ func SendPortalCredentials(c *fiber.Ctx) error {
|
||||
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)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user