package controllers import ( "strconv" "strings" "github.com/gofiber/fiber/v2" "github.com/sujit-baniya/fiber-boilerplate/pkg/models" "github.com/sujit-baniya/fiber-boilerplate/pkg/services" ) // ─── Cuentas de correo IMAP (solo lectura) ─────────────────────────────────── // // Viven en "Lo que sabe": el dueño le pide al agente "revisame los correos de // hoy y resumime" y el agente consulta la casilla en ese momento — nada de // fondo, nada de polling. Para que el agente RESPONDA correos está el canal // de correo en "Dónde atiende", que es otra cosa y tiene otras guardas. // CrearConexionImapHandler conecta una casilla por IMAP. Se prueba ANTES de // guardar: una contraseña mal cargada tiene que fallar acá, con la persona // mirando, y no después dentro de una conversación. // POST /umind/conexiones/imap func CrearConexionImapHandler(c *fiber.Ctx) error { var req struct { AgenteID uint `json:"agente_id"` Email string `json:"email"` Host string `json:"host"` Puerto int `json:"puerto"` Password string `json:"password"` Encriptado string `json:"encriptado"` } if err := c.BodyParser(&req); err != nil { return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "body inválido"}) } if _, err := accesoAgente(c, req.AgenteID); err != nil { return err } email := strings.ToLower(strings.TrimSpace(req.Email)) if email == "" || !strings.Contains(email, "@") { return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "poné la dirección de la casilla, ej: ventas@tunegocio.com"}) } if strings.TrimSpace(req.Password) == "" { return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "falta la contraseña de la casilla"}) } // Sin host se prueba el clásico mail.: en hosting común acierta // casi siempre y el cliente no ve un solo campo técnico. host := strings.TrimSpace(req.Host) if host == "" { host = "mail." + strings.SplitN(email, "@", 2)[1] } cred := services.CredencialesIMAP{ Host: host, Puerto: req.Puerto, Usuario: email, Password: req.Password, Encriptado: req.Encriptado, } if err := services.ProbarConexionIMAPGenerica(cred); err != nil { return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{ "error": "la casilla rechazó la conexión: " + err.Error() + " — si tu correo es de Gmail u Outlook, usá los botones de conectar con Google/Microsoft", }) } enc, err := services.CifrarCredencialesIMAP(cred) if err != nil { return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": err.Error()}) } conexion := &models.UmindConexion{ AgenteID: req.AgenteID, Proveedor: "imap", Email: email, CredencialesEnc: enc, Activo: true, } if err := models.CreateUmindConexion(conexion); err != nil { return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": err.Error()}) } return c.Status(fiber.StatusCreated).JSON(fiber.Map{"ok": true, "id": conexion.ID, "host": host}) } // ProbarConexionImapAgenteHandler reconecta una cuenta ya guardada y dice si // sigue andando — la contraseña pudo cambiar del lado del cliente. // POST /umind/conexiones/:id/probar func ProbarConexionImapAgenteHandler(c *fiber.Ctx) error { id, err := strconv.ParseUint(c.Params("id"), 10, 64) if err != nil { return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "id inválido"}) } if err := accesoConexion(c, uint(id)); err != nil { return err } conexion, err := models.GetUmindConexionByID(uint(id)) if err != nil { return errSinAcceso(c) } if conexion.Proveedor != "imap" { return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "esta cuenta es OAuth: se prueba sola al usarse"}) } cred, err := services.DescifrarCredencialesIMAP(conexion.CredencialesEnc) if err != nil { return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "credenciales corruptas"}) } if err := services.ProbarConexionIMAPGenerica(cred); err != nil { return c.Status(fiber.StatusBadGateway).JSON(fiber.Map{"error": err.Error()}) } return c.JSON(fiber.Map{"ok": true, "message": "La casilla responde bien"}) }