252 lines
6.8 KiB
Go
Executable File
252 lines
6.8 KiB
Go
Executable File
package controllers
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"image/png"
|
|
"log"
|
|
"os"
|
|
"strings"
|
|
|
|
"github.com/chai2010/webp"
|
|
"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 CreateQr(c *fiber.Ctx) error {
|
|
var data services.ContactData
|
|
if err := json.Unmarshal(c.Body(), &data); err != nil {
|
|
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
|
|
"error": "Datos inválidos",
|
|
})
|
|
}
|
|
|
|
// 1. Generar el QR en formato PNG
|
|
qrBytes, err := services.GenerateVCardQR(data)
|
|
if err != nil {
|
|
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
|
"error": "No se pudo generar el QR",
|
|
})
|
|
}
|
|
|
|
// 2. Decodificar PNG
|
|
img, err := png.Decode(bytes.NewReader(qrBytes))
|
|
if err != nil {
|
|
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
|
"error": "Error al decodificar QR PNG",
|
|
})
|
|
}
|
|
|
|
// 3. Convertir a WebP
|
|
var webpBuf bytes.Buffer
|
|
if err := webp.Encode(&webpBuf, img, nil); err != nil {
|
|
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
|
"error": "Error al convertir QR a WebP",
|
|
})
|
|
}
|
|
|
|
random := helpers.RandomString(4)
|
|
fileName := fmt.Sprintf("qrs/qr-%s-%s.webp", strings.ReplaceAll(data.FirstName, " ", "_"), random)
|
|
tmpPath := fmt.Sprintf("/tmp/%s.webp", data.FirstName)
|
|
|
|
// 4. Guardar archivo temporal
|
|
if err := os.WriteFile(tmpPath, webpBuf.Bytes(), 0644); err != nil {
|
|
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
|
"error": "No se pudo guardar el QR temporalmente",
|
|
})
|
|
}
|
|
defer os.Remove(tmpPath)
|
|
|
|
// 5. Subir a OSS
|
|
ossService, err := services.NewOSSServiceFromDB()
|
|
if err != nil {
|
|
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
|
"error": "Error de conexión con OSS",
|
|
})
|
|
}
|
|
|
|
if err := ossService.UploadFile(fileName, tmpPath); err != nil {
|
|
log.Printf("Error subiendo archivo a OSS: %v", err)
|
|
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
|
"error": "Error subiendo archivo a OSS",
|
|
})
|
|
}
|
|
|
|
// 6. URL del archivo
|
|
url := fmt.Sprintf("https://%s.%s/%s", ossService.BucketName, ossService.Endpoint, fileName)
|
|
|
|
// 7. Buscar si ya existe un registro con ese vcard_id
|
|
var existing models.QrVcard
|
|
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
|
|
newQr := models.QrVcard{
|
|
Qr: url,
|
|
UsuarioID: data.FirstName,
|
|
Email: data.Email,
|
|
VcardID: data.VcardID,
|
|
}
|
|
if err := models.CreateQrVcard(&newQr); err != nil {
|
|
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
|
"error": "Error al guardar nuevo QR en la base de datos",
|
|
})
|
|
}
|
|
} else {
|
|
// Otro error
|
|
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
|
"error": "Error al consultar la base de datos",
|
|
})
|
|
}
|
|
} else {
|
|
// Ya existe, eliminar el QR anterior en OSS
|
|
oldFilePath := strings.Replace(existing.Qr, fmt.Sprintf("https://%s.%s/", ossService.BucketName, ossService.Endpoint), "", 1)
|
|
|
|
if err := ossService.DeleteFile(oldFilePath); err != nil {
|
|
log.Printf("Error al eliminar QR anterior en OSS: %v", err)
|
|
// No retornamos error, porque queremos continuar de todas formas
|
|
}
|
|
|
|
// Actualizar el registro
|
|
existing.Qr = url
|
|
existing.UsuarioID = data.FirstName
|
|
existing.Email = data.Email
|
|
|
|
if err := models.UpdateQrVcard(&existing); err != nil {
|
|
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
|
"error": "Error al actualizar el QR en la base de datos",
|
|
})
|
|
}
|
|
}
|
|
|
|
// 8. Retornar la URL
|
|
return c.JSON(fiber.Map{
|
|
"url": url,
|
|
})
|
|
}
|
|
|
|
func CreateQrTmp(c *fiber.Ctx) error {
|
|
var data services.ContactData
|
|
if err := json.Unmarshal(c.Body(), &data); err != nil {
|
|
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
|
|
"error": "Datos inválidos",
|
|
})
|
|
}
|
|
|
|
qrBytes, err := services.GenerateVCardQR(data)
|
|
if err != nil {
|
|
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
|
"error": "No se pudo generar el QR",
|
|
})
|
|
}
|
|
|
|
// Decodificar PNG
|
|
img, err := png.Decode(bytes.NewReader(qrBytes))
|
|
if err != nil {
|
|
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
|
"error": "No se pudo procesar la imagen",
|
|
})
|
|
}
|
|
|
|
// Codificar a WebP
|
|
var webpBuffer bytes.Buffer
|
|
if err := webp.Encode(&webpBuffer, img, &webp.Options{Lossless: true}); err != nil {
|
|
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
|
"error": "No se pudo convertir a WebP",
|
|
})
|
|
}
|
|
|
|
c.Type("webp")
|
|
return c.Send(webpBuffer.Bytes())
|
|
}
|
|
|
|
func CreateUrlQr(c *fiber.Ctx) error {
|
|
var data struct {
|
|
URL string `json:"url"`
|
|
Nombre string `json:"unico"`
|
|
}
|
|
if err := json.Unmarshal(c.Body(), &data); err != nil {
|
|
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
|
|
"error": "Datos inválidos",
|
|
})
|
|
}
|
|
|
|
qrBytes, err := services.GenerateURlQR(data.URL)
|
|
if err != nil {
|
|
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
|
"error": "No se pudo generar el QR",
|
|
})
|
|
}
|
|
|
|
img, err := png.Decode(bytes.NewReader(qrBytes))
|
|
if err != nil {
|
|
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
|
"error": "No se pudo procesar la imagen",
|
|
})
|
|
}
|
|
|
|
// Codificar a WebP
|
|
var webpBuffer bytes.Buffer
|
|
if err := webp.Encode(&webpBuffer, img, &webp.Options{Lossless: true}); err != nil {
|
|
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
|
"error": "No se pudo convertir a WebP",
|
|
})
|
|
}
|
|
|
|
// 3. Convertir a WebP
|
|
var webpBuf bytes.Buffer
|
|
if err := webp.Encode(&webpBuf, img, nil); err != nil {
|
|
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
|
"error": "Error al convertir QR a WebP",
|
|
})
|
|
}
|
|
|
|
|
|
fileName := fmt.Sprintf("qrs/url/qr-%s.webp", strings.ReplaceAll(data.Nombre, " ", "_") )
|
|
tmpPath := fmt.Sprintf("/tmp/%s.webp", data.Nombre)
|
|
|
|
// 4. Guardar archivo temporal
|
|
if err := os.WriteFile(tmpPath, webpBuf.Bytes(), 0644); err != nil {
|
|
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
|
"error": "No se pudo guardar el QR temporalmente",
|
|
})
|
|
}
|
|
defer os.Remove(tmpPath)
|
|
|
|
// 5. Subir a OSS
|
|
ossService, err := services.NewOSSServiceFromDB()
|
|
if err != nil {
|
|
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
|
"error": "Error de conexión con OSS",
|
|
})
|
|
}
|
|
|
|
if err := ossService.UploadFile(fileName, tmpPath); err != nil {
|
|
log.Printf("Error subiendo archivo a OSS: %v", err)
|
|
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
|
"error": "Error subiendo archivo a OSS",
|
|
})
|
|
}
|
|
|
|
// 6. URL del archivo
|
|
url := fmt.Sprintf("https://%s.%s/%s", ossService.BucketName, ossService.Endpoint, fileName)
|
|
|
|
|
|
|
|
// 8. Retornar la URL
|
|
return c.JSON(fiber.Map{
|
|
"url": url,
|
|
})
|
|
}
|
|
|