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:
categoryen 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
- Frontend envía
categorypor master (entrada de usuario o global como fallback). - Backend crea Stencil con esa
categoryexacta. - Respuesta incluye
categoryen 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_pathya fue sanitizado enanalyze_visio()(v1.52.0 PR 1/3); solo se persiste si es seguro. - No path traversal:
image_pathes una ruta relativa validada contraMEDIA_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ódigo | Escenario |
|---|---|
| 200 | ✅ Importación exitosa. |
| 400 | Malformed JSON, sesión no encontrada, masters vacía. |
| 401 | No autenticado. |
| 403 | Organization RLS violation (no pertenece a la org). |
| 500 | Error en creación de Stencil (DB, FS). |
Cambios en v1.53.0
- Adición de
categorypor master en request y response (fue v1.53.0). - Removal de
category_nameglobal — la respuesta sigue sin usarla, el frontend agrupa dinámicamente. - Test:
test_confirm_per_shape_categoriesverifica 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]]