Files
soft_usite/rest/controllers/api/vcard_vcf.go
T
Lizandro GuarnizoandClaude Opus 5 17ed57cb56 fix(vcard): decir por qué falla la subida a OSS, y no armar la clave con texto crudo del cliente
El sistema que consume /v2/vcard/qr-url solo recibía "Error subiendo archivo a
OSS": el motivo quedaba en nuestro log y del otro lado no había nada que hacer
con eso. Ahora la respuesta incluye el error real del proveedor —es una API
entre servidores y el que llama ya conoce la config de OSS que mandó— y el log
dice además qué clave se intentó subir.

La clave del objeto se armaba con el nombre tal como venía en el body. Un
nombre con "/" o con caracteres que OSS no acepta producía justamente ese
error genérico. Ahora se limpia.

El mismo nombre crudo se usaba para el archivo temporal (/tmp/<nombre>.webp),
o sea escritura de archivos en una ruta que elegía quien llamaba. Se fue
entero: los tres endpoints suben desde memoria con UploadFromReader, que
además saca el paso a disco y su limpieza.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-17 20:04:34 -05:00

99 lines
2.8 KiB
Go
Executable File

package controllers
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"log"
"github.com/gofiber/fiber/v2"
"github.com/sujit-baniya/fiber-boilerplate/app"
"github.com/sujit-baniya/fiber-boilerplate/pkg/helpers"
"github.com/sujit-baniya/fiber-boilerplate/pkg/models"
"github.com/sujit-baniya/fiber-boilerplate/pkg/services"
"gorm.io/gorm"
// Importa el repositorio
)
func CreateVcf(c *fiber.Ctx) error {
var data services.ContactDataVcf
if err := json.Unmarshal(c.Body(), &data); err != nil {
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
"error": "Datos inválidos",
})
}
// 1. Generar el Vcf
vcfContent, err := services.GenerateVCardVcf(data)
if err != nil {
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
"error": "No se pudo generar el VCF",
})
}
random := helpers.RandomString(4)
fileName := fmt.Sprintf("vcf/vcf-%s-%s.vcf", claveObjetoSegura(data.FirstName), random)
// 2. Subir a OSS directo desde memoria (ver el comentario en CreateQr).
ossProvider, err := getOSSFromBody(c)
if err != nil {
log.Printf("[VCF] No se pudo resolver la config de OSS: %v", err)
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
"error": "Error de conexión con OSS", "detalle": err.Error(),
})
}
if err := ossProvider.UploadFromReader(fileName, "text/vcard; charset=utf-8", bytes.NewReader(vcfContent)); err != nil {
log.Printf("Error subiendo archivo a OSS (%s): %v", fileName, err)
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
"error": "Error subiendo archivo a OSS", "detalle": err.Error(),
})
}
// 4. URL del archivo
url := ossProvider.PublicURL(fileName)
// 5. Buscar si ya existe un registro con ese vcard_id
var existing models.VcfVcard
db := app.Http.Database.DB
err = db.Where("vcard_id = ?", data.VcardID).First(&existing).Error
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
// No existe, crear nuevo
newVcf := models.VcfVcard{
Vcf: url,
UsuarioID: data.FirstName, // Podrías usar el ID real de usuario si lo tienes
Email: data.Email,
VcardID: data.VcardID,
}
if err := models.CreateVcfVcard(&newVcf); err != nil {
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
"error": "No se pudo crear el registro VCF",
})
}
} else {
// Error inesperado de DB
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
"error": "Error buscando VCF existente",
})
}
} else {
// Si ya existe, actualizar
existing.Vcf = url
existing.Email = data.Email
existing.UsuarioID = data.FirstName
if err := models.UpdateVcfVcard(&existing); err != nil {
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
"error": "No se pudo actualizar el VCF existente",
})
}
}
return c.JSON(fiber.Map{
"success": true,
"url": url,
})
}