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>
69 lines
1.8 KiB
Go
69 lines
1.8 KiB
Go
package controllers
|
|
|
|
import (
|
|
"encoding/json"
|
|
"strings"
|
|
|
|
"github.com/gofiber/fiber/v2"
|
|
"github.com/sujit-baniya/fiber-boilerplate/pkg/models"
|
|
"github.com/sujit-baniya/fiber-boilerplate/pkg/services"
|
|
)
|
|
|
|
// getOSSFromBody creates an OSSProvider from the oss_api_id in the request body.
|
|
// If oss_api_id is missing, it falls back to the last active config (legacy behavior).
|
|
func getOSSFromBody(c *fiber.Ctx) (services.OSSProvider, error) {
|
|
var req struct {
|
|
OssAPIID *uint `json:"oss_api_id"`
|
|
}
|
|
if err := json.Unmarshal(c.Body(), &req); err != nil {
|
|
req.OssAPIID = nil
|
|
}
|
|
|
|
if req.OssAPIID != nil {
|
|
return services.NewOSSProviderByID(*req.OssAPIID)
|
|
}
|
|
return services.NewOSSProviderFromDB()
|
|
}
|
|
|
|
// getOSSFromQuery creates an OSSProvider from the oss_api_id query param.
|
|
// If missing, falls back to last active config.
|
|
func getOSSFromQuery(c *fiber.Ctx) (services.OSSProvider, error) {
|
|
id := c.QueryInt("oss_api_id", 0)
|
|
if id > 0 {
|
|
return services.NewOSSProviderByID(uint(id))
|
|
}
|
|
|
|
lastActive, err := models.GetLastActiveOssApi()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return services.NewOSSProvider(lastActive)
|
|
}
|
|
|
|
// claveObjetoSegura arma una clave de objeto a partir de texto que viene del
|
|
// cliente. Sin esto, un nombre con "/" o con caracteres de control produce una
|
|
// clave que OSS rechaza — y el que llama solo ve "error subiendo a OSS".
|
|
func claveObjetoSegura(nombre string) string {
|
|
nombre = strings.TrimSpace(nombre)
|
|
limpio := strings.Map(func(r rune) rune {
|
|
switch {
|
|
case r >= 'a' && r <= 'z', r >= 'A' && r <= 'Z', r >= '0' && r <= '9':
|
|
return r
|
|
case r == '-', r == '_', r == '.':
|
|
return r
|
|
case r == ' ':
|
|
return '_'
|
|
default:
|
|
return -1
|
|
}
|
|
}, nombre)
|
|
limpio = strings.Trim(limpio, "._-")
|
|
if limpio == "" {
|
|
return "sin-nombre"
|
|
}
|
|
if len(limpio) > 80 {
|
|
limpio = limpio[:80]
|
|
}
|
|
return limpio
|
|
}
|