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]]