Entidadactivecreado Mon Jun 08#network#auto-provision#endpoint#api#multi-tenancy#rls#rest#sesion-115
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:
- Validación de permisos: requiere
network.edit. - Sanitización de name: recorta espacios en blanco, limita a 255 caracteres; default “Untitled scan” si queda vacío.
- Filtrado de perfiles: solo acepta IDs de
DeviceProfileque pertenecen a la org del usuario. Perfiles de otros tenants se descartan silenciosamente (sin error). - Creación: inserta el registro con
created_by= usuario actual (NULL si es JWT/anónimo). - Poda automática: si la org ya tiene ≥20 búsquedas, borra las más antiguas, manteniendo solo 20 recientes.
- Auditoría: llama a
log_action(request, "NETWORK", "auto_provision.scan_saved", name). - 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 siget_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:
- Requiere
network.edit. - Intenta eliminar el registro
session_idcuyaorganizationcoincida con la del usuario (RLS). - Si no existe o pertenece a otra org, retorna 404.
- 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()realizaGET /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:
_savedScansCachealmacena el resultado de GET en memoria para operaciones índice-basadas (Load/Delete por fila).
Constantes
| Nombre | Valor | Descripción |
|---|---|---|
MAX_SESSIONS | 20 | Máximo de búsquedas por org |
SCANS_API (JS) | /api/network/auto-provision/scans | URL base del endpoint |
Manejo de Errores
| Escenario | HTTP | Respuesta |
|---|---|---|
| Usuario sin org (raro) | 400 | {"error": "No organization found"} |
| Borrar búsqueda de otra org | 404 | {"error": "Scan session not found"} |
| GET con usuario sin org | 200 | [] (vacío) |
| POST con perfil de otra org | 200 | Se 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]]