Descripción
Ruta: POST /api/racks/visio/confirm
Endpoint que toma la lista de masters (formas/stencils convertidas o analizadas) y los persiste en la librería permanente del tenant. Cierre final de seguridad: todos los SVG se sanitizan de nuevo antes de guardar.
Parámetros (body JSON)
{
"session_id": "uuid-string",
"masters": [
{
"name": "Cisco Rack (page 1)",
"image_path": "uploads/temp/uuid.../page1.svg",
"u_height": 1
},
...
],
"category_name": "Cisco Equipment"
}
Campos:
session_id(required): UUID de la sesión generada poranalyzemasters(required): lista de objetos master a importar. Cada uno tiene:name: display name del stencilimage_path: ruta relativa aMEDIA_ROOT(del temp) o absoluta del ficherou_height: altura de unidad (rack units ocupadas por defecto; puede ser 1)
category_name(required): categoría destino en la librería (ej. “Cisco”, “APC”)
Respuesta (200)
{
"imported": [
{
"id": 123,
"name": "Cisco Rack (page 1)",
"category": "Cisco Equipment"
}
]
}
Campo imported: lista de Stencil objetos creados exitosamente (con id, name, category).
Flujo interno
- Validación de org: requiere Organization en context
- Validación de permisos:
require_perm(..., "racks", "admin")— fix s220 - Lectura de session: obtiene estado de
temp/{session_id}/visio_session.json - Iteración sobre masters solicitados:
- Valida
image_path(no.../que escape MEDIA_ROOT) — fix s220 - Sanitiza el SVG si es necesario — fix s220 (defensa en profundidad)
- Si fichero no existe o validación falla, salta ese master (no error 400)
- Valida
- Persistencia: mueve fichero de temp a
uploads/stencils/con nombre único - Modelo: crea
Stencilcon FK aorganization, categoría, imagen, altura
Seguridad
Fix s220: 3 capas
- Permisos (racks:admin): solo administradores pueden persistir stencils
- Path-traversal guard:
image_pathvalidado conrealpath()+ prefijo - Sanitización final: todos los SVG se limpian de XSS antes de guardar (segundo pass, defensa en profundidad)
Todos implementados en v1.52.0.
Códigos de respuesta
| Código | Condición |
|---|---|
200 | Uno o más masters importados exitosamente |
400 | Sin org, session_id inválido, payload malformado |
403 | Usuario sin permisos racks:admin |
500 | Error interno (excepción en lógica) |
Testing
Cubierto en tests/api/test_visio_import_v2.py y tests/api/test_racks_visio_confirm.py:
- Permisos: operator/viewer → 403 (fix s220)
- Path-traversal: intento de
../se ignora silenciosamente (fix s220) - Sanitización: SVG malicioso persiste limpio (fix s220)
- Noop vacío: masters = [] → 200, imported = [] (idempotente)
Modelo destino
Stencil (racks/models.py):
organization(FK a Organization) — RLS boundarycategory(CharField) — agrupa stencilsname(CharField) — displayimage_path(FileField) — ruta dentro de MEDIA_ROOTu_height(IntegerField) — unidades rack por defectocreated_at(DateTimeField)
Ciclo de vida completo
- Cliente POST
/api/racks/visio/analyzecon fichero - Backend encola conversión (async o sync)
- Cliente GET
/api/racks/visio/session/{id}hastastatus=done - Cliente obtiene lista de masters, selecciona cuáles importar
- Cliente POST
/api/racks/visio/confirmcon masters seleccionados + categoría - Backend persiste en
Stencil+ fichero enuploads/stencils/ - Librería del tenant ahora incluye los stencils
Véase también
- [[feature—racks—import-visio-v2]]
- [[entity—racks—endpoint—visio-analyze]]
- [[entity—racks—endpoint—visio-session-status]]
- [[entity—racks—service—svg-sanitizer]]
- [[entity—racks—model—stencil]]
- [[decision—20260713—visio-confirm-hardening]]