CreaRack-SL

Endpoint: GET/POST/DELETE /auto-provision/scans

Descripción

Endpoint REST que persiste las búsquedas guardadas de Auto-Provision en BD, reemplazando el localStorage del navegador. Accesible en tres métodos: listado, creación y borrado.

Ubicación: network/api/scan_sessions.py (router registrado en network/api/__init__.py)

Operaciones

GET /auto-provision/scans

Permisos: network.view (RLS)

Respuesta:

[
  {
    "id": 42,
    "name": "10.0.0.0/24",
    "created_at": "2026-06-08T14:05:00Z",
    "device_count": 5,
    "profile_ids": [12, 13, 14, 15, 16]
  },
  ...
]

Comportamiento:

  • Retorna búsquedas de la organización actual del usuario (filtrado por get_current_org).
  • Ordenadas descendente por created_at (más recientes primero).
  • Máximo 20 registros (limitados con [:MAX_SESSIONS]).
  • Usa prefetch_related("profiles") para evitar N+1.
  • Si no hay org o no hay búsquedas, retorna lista vacía ([]).

Códigos HTTP:

  • 200 OK: Listado generado (vacío o con entradas).

POST /auto-provision/scans

Permisos: network.edit (RLS)

Request:

{
  "name": "10.0.0.0/24",
  "profile_ids": [12, 13, 14]
}

Respuesta (200 OK):

{
  "id": 43,
  "name": "10.0.0.0/24",
  "created_at": "2026-06-08T14:06:00Z",
  "device_count": 3,
  "profile_ids": [12, 13, 14]
}

Comportamiento:

  1. Validación de permisos: requiere network.edit.
  2. Sanitización de name: recorta espacios en blanco, limita a 255 caracteres; default “Untitled scan” si queda vacío.
  3. Filtrado de perfiles: solo acepta IDs de DeviceProfile que pertenecen a la org del usuario. Perfiles de otros tenants se descartan silenciosamente (sin error).
  4. Creación: inserta el registro con created_by = usuario actual (NULL si es JWT/anónimo).
  5. Poda automática: si la org ya tiene ≥20 búsquedas, borra las más antiguas, manteniendo solo 20 recientes.
  6. Auditoría: llama a log_action(request, "NETWORK", "auto_provision.scan_saved", name).
  7. Respuesta: retorna la sesión creada con prefetch de perfiles.

Códigos HTTP:

  • 200 OK: Sesión creada.
  • 400 Bad Request: No se encontró organización (rarísimo; solo si get_current_org() falla).

DELETE /auto-provision/scans/{session_id}

Permisos: network.edit (RLS)

Respuesta (200 OK):

{"success": true}

Respuesta (404 Not Found):

{"error": "Scan session not found"}

Comportamiento:

  1. Requiere network.edit.
  2. Intenta eliminar el registro session_id cuya organization coincida con la del usuario (RLS).
  3. Si no existe o pertenece a otra org, retorna 404.
  4. Si existe y es de la org, lo borra y retorna 200.

Códigos HTTP:

  • 200 OK: Borrado exitoso.
  • 404 Not Found: No existe o no pertenece a la org.

Esquemas Ninja

ScanSessionOut (Schema)

Respuesta serializada de lectura.

class ScanSessionOut(Schema):
    id: int
    name: str
    created_at: datetime
    device_count: int  # Calculado en vivo desde profiles.all()
    profile_ids: list[int]  # Lista de IDs de DeviceProfile

ScanSessionCreate (Schema)

Payload esperado en POST.

class ScanSessionCreate(Schema):
    name: str  # Etiqueta del escaneo
    profile_ids: list[int] = []  # Perfiles asociados (default vacía)

Integración con el Frontend

Archivo: static/js/network/auto_provision/sessions.js

  • Carga inicial: loadSavedProfiles() realiza GET /auto-provision/scans.
  • Guardar búsqueda: _saveScanSession(name, profileIds) → POST /auto-provision/scans.
  • Borrar búsqueda: _removeScanByIndex(index) → DELETE /auto-provision/scans/{id}.
  • Caché local: _savedScansCache almacena el resultado de GET en memoria para operaciones índice-basadas (Load/Delete por fila).

Constantes

NombreValorDescripción
MAX_SESSIONS20Máximo de búsquedas por org
SCANS_API (JS)/api/network/auto-provision/scansURL base del endpoint

Manejo de Errores

EscenarioHTTPRespuesta
Usuario sin org (raro)400{"error": "No organization found"}
Borrar búsqueda de otra org404{"error": "Scan session not found"}
GET con usuario sin org200[] (vacío)
POST con perfil de otra org200Se crea, pero perfil se descarta (silent)

Auditoría y Logs

  • Evento: log_action(request, "NETWORK", "auto_provision.scan_saved", name)
  • Disparado: Cada vez que se crea una nueva búsqueda.
  • Campo: name (la etiqueta del escaneo).

Tests

Archivo: tests/api/test_network_scan_sessions.py

Cubre:

  • ✅ Permisos (viewer no puede crear/borrar, solo listar).
  • ✅ Creación y vinculación de perfiles.
  • ✅ Aislamiento org (perfil de otra org es ignorado).
  • ✅ Poda a 20 máximo.
  • ✅ Listado ordena recientes primero.
  • ✅ Borrado propio y cross-org 404.

Historial

  • s115 (2026-06-08): Introducido. Reemplaza localStorage.

Véase también

  • [[entity—network—model—scan-session]]
  • [[entity—network—model—device-profile]]
  • [[feature—auto-provision—sesion-115-busquedas-persistidas]]
  • [[concept—saas—multi-tenancy]]
  • [[concept—auto-provision—ciclo-escaneo]]