feat: add VCard API integration with configuration and proxy endpoints
- Implemented VCard API controller with methods to manage configuration (save, get). - Added proxy functions to handle API requests for users, vcards, memberships, payments, transactions, logs, and miniwebs. - Included error handling and response formatting for API interactions.
This commit is contained in:
@@ -0,0 +1,248 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/sujit-baniya/fiber-boilerplate/pkg/models"
|
||||
)
|
||||
|
||||
// VcardApiIndex renderiza el panel de integración VCard.
|
||||
func VcardApiIndex(c *fiber.Ctx) error {
|
||||
cfg, _ := models.GetVcardApiConfig()
|
||||
data := fiber.Map{
|
||||
"user": c.Locals("user").(map[string]interface{}),
|
||||
"modules": c.Locals("userModules"),
|
||||
"config": cfg,
|
||||
}
|
||||
return c.Render("vcard_api", data, "layouts/main")
|
||||
}
|
||||
|
||||
// VcardApiSaveConfig guarda / actualiza la configuración (base URL + token).
|
||||
func VcardApiSaveConfig(c *fiber.Ctx) error {
|
||||
type Req struct {
|
||||
Nombre string `json:"nombre"`
|
||||
BaseURL string `json:"base_url"`
|
||||
BearerToken string `json:"bearer_token"`
|
||||
Activo bool `json:"activo"`
|
||||
}
|
||||
var req Req
|
||||
if err := c.BodyParser(&req); err != nil {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "body inválido"})
|
||||
}
|
||||
if strings.TrimSpace(req.BaseURL) == "" {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "base_url es requerido"})
|
||||
}
|
||||
cfg, err := models.UpsertVcardApiConfig(req.Nombre, strings.TrimRight(strings.TrimSpace(req.BaseURL), "/"), req.BearerToken, req.Activo)
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": err.Error()})
|
||||
}
|
||||
return c.JSON(fiber.Map{"ok": true, "config": cfg})
|
||||
}
|
||||
|
||||
// VcardApiGetConfig devuelve la configuración actual (sin exponer el token completo).
|
||||
func VcardApiGetConfig(c *fiber.Ctx) error {
|
||||
cfg, err := models.GetVcardApiConfig()
|
||||
if err != nil {
|
||||
return c.JSON(fiber.Map{"config": nil})
|
||||
}
|
||||
masked := "••••••••"
|
||||
if cfg.BearerToken == "" {
|
||||
masked = ""
|
||||
}
|
||||
return c.JSON(fiber.Map{
|
||||
"config": fiber.Map{
|
||||
"ID": cfg.ID,
|
||||
"nombre": cfg.Nombre,
|
||||
"base_url": cfg.BaseURL,
|
||||
"bearer_token": masked,
|
||||
"activo": cfg.Activo,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// vcardDo ejecuta una llamada a la API Admin VCard y devuelve el body como json.RawMessage.
|
||||
func vcardDo(method, endpoint string, cfg *models.VcardApiConfig) ([]byte, int, error) {
|
||||
return vcardDoWithBody(method, endpoint, nil, "", cfg)
|
||||
}
|
||||
|
||||
// vcardDoWithBody ejecuta una llamada a la API Admin VCard con body opcional.
|
||||
func vcardDoWithBody(method, endpoint string, reqBody io.Reader, contentType string, cfg *models.VcardApiConfig) ([]byte, int, error) {
|
||||
url := fmt.Sprintf("%s%s", cfg.BaseURL, endpoint)
|
||||
client := &http.Client{Timeout: 15 * time.Second}
|
||||
req, err := http.NewRequest(method, url, reqBody)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
req.Header.Set("Authorization", "Bearer "+cfg.BearerToken)
|
||||
req.Header.Set("Accept", "application/json")
|
||||
if contentType != "" {
|
||||
req.Header.Set("Content-Type", contentType)
|
||||
}
|
||||
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
body, _ := io.ReadAll(io.LimitReader(resp.Body, 512*1024))
|
||||
return body, resp.StatusCode, nil
|
||||
}
|
||||
|
||||
// proxyVcard extrae la config, llama al endpoint y devuelve el resultado al frontend.
|
||||
func proxyVcard(c *fiber.Ctx, method, endpoint string) error {
|
||||
cfg, err := models.GetVcardApiConfig()
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "Configura primero la API VCard"})
|
||||
}
|
||||
if !cfg.Activo {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "La integración está inactiva"})
|
||||
}
|
||||
|
||||
qs := string(c.Request().URI().QueryString())
|
||||
ep := endpoint
|
||||
if qs != "" {
|
||||
ep = endpoint + "?" + qs
|
||||
}
|
||||
|
||||
body, status, err := vcardDo(method, ep, cfg)
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusBadGateway).JSON(fiber.Map{"error": err.Error()})
|
||||
}
|
||||
var result json.RawMessage
|
||||
if err := json.Unmarshal(body, &result); err != nil {
|
||||
result = json.RawMessage(fmt.Sprintf(`{"raw": %q}`, string(body)))
|
||||
}
|
||||
c.Status(status)
|
||||
return c.JSON(result)
|
||||
}
|
||||
|
||||
// proxyVcardMutate reenvía el body del request original a la API VCard.
|
||||
func proxyVcardMutate(c *fiber.Ctx, method, endpoint string) error {
|
||||
cfg, err := models.GetVcardApiConfig()
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "Configura primero la API VCard"})
|
||||
}
|
||||
if !cfg.Activo {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "La integración está inactiva"})
|
||||
}
|
||||
|
||||
var bodyReader io.Reader
|
||||
ct := ""
|
||||
if raw := c.Body(); len(raw) > 0 {
|
||||
bodyReader = strings.NewReader(string(raw))
|
||||
ct = c.Get("Content-Type", "application/json")
|
||||
}
|
||||
|
||||
body, status, err := vcardDoWithBody(method, endpoint, bodyReader, ct, cfg)
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusBadGateway).JSON(fiber.Map{"error": err.Error()})
|
||||
}
|
||||
var result json.RawMessage
|
||||
if err := json.Unmarshal(body, &result); err != nil {
|
||||
result = json.RawMessage(fmt.Sprintf(`{"raw": %q}`, string(body)))
|
||||
}
|
||||
c.Status(status)
|
||||
return c.JSON(result)
|
||||
}
|
||||
|
||||
// ─── Proxy endpoints ──────────────────────────────────────────────────────────
|
||||
|
||||
func VcardApiUsuarios(c *fiber.Ctx) error {
|
||||
return proxyVcard(c, http.MethodGet, "/api/admin/usuarios")
|
||||
}
|
||||
|
||||
func VcardApiUsuario(c *fiber.Ctx) error {
|
||||
return proxyVcard(c, http.MethodGet, "/api/admin/usuarios/"+c.Params("id"))
|
||||
}
|
||||
|
||||
func VcardApiVcards(c *fiber.Ctx) error {
|
||||
return proxyVcard(c, http.MethodGet, "/api/admin/vcards")
|
||||
}
|
||||
|
||||
func VcardApiVcard(c *fiber.Ctx) error {
|
||||
return proxyVcard(c, http.MethodGet, "/api/admin/vcards/"+c.Params("id"))
|
||||
}
|
||||
|
||||
func VcardApiVcardsByUsuario(c *fiber.Ctx) error {
|
||||
return proxyVcard(c, http.MethodGet, "/api/admin/usuarios/"+c.Params("userId")+"/vcards")
|
||||
}
|
||||
|
||||
func VcardApiPlanes(c *fiber.Ctx) error {
|
||||
return proxyVcard(c, http.MethodGet, "/api/admin/planes")
|
||||
}
|
||||
|
||||
func VcardApiMembresia(c *fiber.Ctx) error {
|
||||
return proxyVcard(c, http.MethodGet, "/api/admin/usuarios/"+c.Params("id")+"/membresia")
|
||||
}
|
||||
|
||||
func VcardApiPagos(c *fiber.Ctx) error {
|
||||
return proxyVcard(c, http.MethodGet, "/api/admin/pagos")
|
||||
}
|
||||
|
||||
func VcardApiPagosByUsuario(c *fiber.Ctx) error {
|
||||
return proxyVcard(c, http.MethodGet, "/api/admin/usuarios/"+c.Params("userId")+"/pagos")
|
||||
}
|
||||
|
||||
func VcardApiTransacciones(c *fiber.Ctx) error {
|
||||
return proxyVcard(c, http.MethodGet, "/api/admin/transacciones")
|
||||
}
|
||||
|
||||
func VcardApiTransaccionesByUsuario(c *fiber.Ctx) error {
|
||||
return proxyVcard(c, http.MethodGet, "/api/admin/usuarios/"+c.Params("userId")+"/transacciones")
|
||||
}
|
||||
|
||||
func VcardApiLogs(c *fiber.Ctx) error {
|
||||
return proxyVcard(c, http.MethodGet, "/api/admin/logs")
|
||||
}
|
||||
|
||||
func VcardApiLogsByUsuario(c *fiber.Ctx) error {
|
||||
return proxyVcard(c, http.MethodGet, "/api/admin/usuarios/"+c.Params("userId")+"/logs")
|
||||
}
|
||||
|
||||
func VcardApiMiniwebs(c *fiber.Ctx) error {
|
||||
return proxyVcard(c, http.MethodGet, "/api/admin/miniwebs")
|
||||
}
|
||||
|
||||
func VcardApiMiniweb(c *fiber.Ctx) error {
|
||||
return proxyVcard(c, http.MethodGet, "/api/admin/miniwebs/"+c.Params("id"))
|
||||
}
|
||||
|
||||
func VcardApiMiniwebsByUsuario(c *fiber.Ctx) error {
|
||||
return proxyVcard(c, http.MethodGet, "/api/admin/usuarios/"+c.Params("userId")+"/miniwebs")
|
||||
}
|
||||
|
||||
// ─── Mutación endpoints ───────────────────────────────────────────────────────
|
||||
|
||||
func VcardApiUsuarioUpdate(c *fiber.Ctx) error {
|
||||
return proxyVcardMutate(c, http.MethodPut, "/api/admin/usuarios/"+c.Params("id"))
|
||||
}
|
||||
|
||||
func VcardApiUsuarioActivar(c *fiber.Ctx) error {
|
||||
return proxyVcardMutate(c, http.MethodPost, "/api/admin/usuarios/"+c.Params("id")+"/activar")
|
||||
}
|
||||
|
||||
func VcardApiUsuarioDesactivar(c *fiber.Ctx) error {
|
||||
return proxyVcardMutate(c, http.MethodPost, "/api/admin/usuarios/"+c.Params("id")+"/desactivar")
|
||||
}
|
||||
|
||||
func VcardApiVcardUpdate(c *fiber.Ctx) error {
|
||||
return proxyVcardMutate(c, http.MethodPut, "/api/admin/vcards/"+c.Params("id"))
|
||||
}
|
||||
|
||||
func VcardApiActivarMembresia(c *fiber.Ctx) error {
|
||||
return proxyVcardMutate(c, http.MethodPost, "/api/admin/usuarios/"+c.Params("id")+"/activar-membresia")
|
||||
}
|
||||
|
||||
func VcardApiDesactivarMembresia(c *fiber.Ctx) error {
|
||||
return proxyVcardMutate(c, http.MethodPost, "/api/admin/usuarios/"+c.Params("id")+"/desactivar-membresia")
|
||||
}
|
||||
|
||||
func VcardApiCambiarPlan(c *fiber.Ctx) error {
|
||||
return proxyVcardMutate(c, http.MethodPost, "/api/admin/usuarios/"+c.Params("id")+"/cambiar-plan")
|
||||
}
|
||||
Reference in New Issue
Block a user