CreaRack-SL

Endpoint: POST /api/racks/visio/confirm — persistencia de stencils importados

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 por analyze
  • masters (required): lista de objetos master a importar. Cada uno tiene:
    • name: display name del stencil
    • image_path: ruta relativa a MEDIA_ROOT (del temp) o absoluta del fichero
    • u_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

  1. Validación de org: requiere Organization en context
  2. Validación de permisos: require_perm(..., "racks", "admin") — fix s220
  3. Lectura de session: obtiene estado de temp/{session_id}/visio_session.json
  4. 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)
  5. Persistencia: mueve fichero de temp a uploads/stencils/ con nombre único
  6. Modelo: crea Stencil con FK a organization, categoría, imagen, altura

Seguridad

Fix s220: 3 capas

  1. Permisos (racks:admin): solo administradores pueden persistir stencils
  2. Path-traversal guard: image_path validado con realpath() + prefijo
  3. 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ódigoCondición
200Uno o más masters importados exitosamente
400Sin org, session_id inválido, payload malformado
403Usuario sin permisos racks:admin
500Error 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 boundary
  • category (CharField) — agrupa stencils
  • name (CharField) — display
  • image_path (FileField) — ruta dentro de MEDIA_ROOT
  • u_height (IntegerField) — unidades rack por defecto
  • created_at (DateTimeField)

Ciclo de vida completo

  1. Cliente POST /api/racks/visio/analyze con fichero
  2. Backend encola conversión (async o sync)
  3. Cliente GET /api/racks/visio/session/{id} hasta status=done
  4. Cliente obtiene lista de masters, selecciona cuáles importar
  5. Cliente POST /api/racks/visio/confirm con masters seleccionados + categoría
  6. Backend persiste en Stencil + fichero en uploads/stencils/
  7. 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]]