CreaRack-SL

Endpoint: POST /api/racks/visio/confirm — Confirmar e importar stencils Visio

Descripción

Endpoint de confirmación que persiste los stencils importados en la base de datos de la organización del usuario autenticado, con categorías individuales por shape (desde v1.53.0).

Ruta: POST /api/racks/visio/confirm
Auth: Django user + Organization RLS
Content-Type: application/json

Contrato de solicitud (v1.53.0+)

{
  "session_id": "uuid-string",
  "masters": [
    {
      "name": "Switch 48-port",
      "image_path": "path/to/preview.svg",
      "u_height": 1,
      "category": "Cisco"
    },
    {
      "name": "PDU",
      "image_path": "path/to/preview.svg",
      "u_height": 2,
      "category": "APC"
    }
  ]
}

Cambio v1.52.0 → v1.53.0:

  • ❌ Removida: category_name (global) — ya no se envía.
  • ✅ Añadido: category en cada master — permite categorías mixtas por shape.

Contrato de respuesta (v1.53.0+)

{
  "success": true,
  "imported": [
    {
      "id": 12345,
      "name": "Switch 48-port",
      "category": "Cisco",
      "image_path": "stencils/cisco/switch.svg",
      "u_height": 1,
      "half_width": false
    },
    {
      "id": 12346,
      "name": "PDU",
      "category": "APC",
      "image_path": "stencils/apc/pdu.svg",
      "u_height": 2,
      "half_width": true
    }
  ]
}

Campos de respuesta por item:

  • id — PK del Stencil creado.
  • name — Nombre elegido (editado inline en el frontend si aplica).
  • category — Categoría del stencil (procede del input por shape, o de la global del modal como fallback).
  • image_path — Ruta relativa a /media/ del SVG.
  • u_height — Altura en unidades rack.
  • half_width — Boolean (ancho medio).

Lógica de negocio

Flujo de categorías

  1. Frontend envía category por master (entrada de usuario o global como fallback).
  2. Backend crea Stencil con esa category exacta.
  3. Respuesta incluye category en cada item → frontend agrupa por categoría y crea carpetas sin recargar.

Seguridad

  • RLS: Stencil creado con organization=request.user.organization.
  • Sanitización SVG: el image_path ya fue sanitizado en analyze_visio() (v1.52.0 PR 1/3); solo se persiste si es seguro.
  • No path traversal: image_path es una ruta relativa validada contra MEDIA_ROOT/temp/{session_id}/.

Límites

  • Session window: la sesión debe existir en MEDIA_ROOT/temp/{session_id}/. Expira en background tras ~4 horas (limpieza cron).
  • Máximo por importación: sin límite explícito; backend respeta timeout de conversión (4 min desde analyze_visio()).

Integración con modelos

Modelo Stencil

class Stencil(models.Model):
    organization = models.ForeignKey(Organization, on_delete=models.CASCADE)
    name = models.CharField(max_length=255)
    category = models.CharField(max_length=255, blank=True, default='')
    image = models.ImageField(upload_to='stencils/')
    svg_content = models.TextField(blank=True)
    u_height = models.IntegerField(default=1)
    half_width = models.BooleanField(default=False)
    created_at = models.DateTimeField(auto_now_add=True)

El endpoint mapea cada master a un Stencil con:

  • organization ← usuario autenticado.
  • name ← nombre editado (o del master original).
  • category ← categoría por shape (del master o global).
  • image / svg_content ← SVG sanitizado + cacheado.
  • u_height ← del master.
  • half_width ← del master.

Manejo de errores

CódigoEscenario
200✅ Importación exitosa.
400Malformed JSON, sesión no encontrada, masters vacía.
401No autenticado.
403Organization RLS violation (no pertenece a la org).
500Error en creación de Stencil (DB, FS).

Cambios en v1.53.0

  • Adición de category por master en request y response (fue v1.53.0).
  • Removal de category_name global — la respuesta sigue sin usarla, el frontend agrupa dinámicamente.
  • Test: test_confirm_per_shape_categories verifica categorías mixtas.

Véase también

  • [[feature—stencils—visio-v2-ui-preview]]
  • [[entity—racks—model—stencil]]
  • [[entity—racks—endpoint—analyze-visio]]
  • [[concept—saas—multi-tenancy]]