# Pruebas del 14-oct — equipo, accesos y responsables Complementa a `TESTS-1013.md`. Todo corrió en el sandbox contra `backend/app.py` con carpetas temporales, un **htpasswd temporal** (`HTPASSWD_FILE`, permisos 640, hashes `$apr1$` generados con la misma rutina del backend) y `ACTAS_ADMINS=leo,alan`. El usuario llega por `X-Remote-User`, como lo fija nginx. ## 1 · Backend — `backend/tests-1014.sh` (57 comprobaciones) ```bash bash backend/tests-1014.sh /ruta/a/hbox-docs 8097 ``` ``` ## siembra (incluye equipo) — con un pendiente viejo sin responsable y sin responsable_ids ✓ equipo sembrado (9) ✓ pendientes nuevos (12 de 13: t-caja-ethernet ya existía) ✓ responsable vacío completado a leo ✓ responsable_ids recalculado ✓ t-caja-ethernet → leo con historial ✓ segunda corrida: equipo no duplica ✓ segunda corrida: nada que completar ✓ t-ferreteria-eit-timsa sembrada para adriana ## equipo ✓ GET equipo (cualquiera) ✓ tiene_login derivado del htpasswd (leo sí) ✓ adriana sin login ✓ es_admin desde ACTAS_ADMINS ✓ pendientes abiertos por miembro ✓ logins sin miembro solo para admin (bob no admin → []) ✓ logins sin miembro para admin (bob) ✓ POST equipo no admin → 403 ✓ POST equipo (admin) ✓ POST equipo duplicado → 409 ✓ POST equipo área inválida → 400 ✓ PATCH miembro no admin → 403 ✓ PATCH miembro (admin) → historial ✓ PATCH activo=false (desactivar, nunca borrar) ✓ GET equipo oculta inactivos ✓ GET equipo?todos=1 los muestra ✓ PATCH inexistente → 404 ## accesos (htpasswd temporal) ✓ POST usuarios no admin → 403 ✓ contraseña corta → 400 ✓ usuario con espacios/mayúsculas → 400 ✓ crea acceso a miembro existente (adriana) ✓ línea en el htpasswd con apr1 ✓ el hash valida con apr1 (misma rutina que /api/password) ✓ permisos del archivo conservados (640) ✓ duplicado → 409 ✓ crea usuario Y miembro nuevos ✓ GET /api/usuarios sigue igual (lista del htpasswd) ✓ la cuenta nueva cambia su propia contraseña por /api/password ✓ bitácora _accesos.csv ✓ DELETE no admin → 403 ✓ DELETE a sí mismo → 400 ✓ DELETE inexistente → 404 ✓ último admin con acceso (alan admin sin login quita a leo) → 409 ✓ con dos admins con acceso, alan sí puede quitar a leo ✓ leo ya no está en el htpasswd ✓ miembro leo desactivado (no borrado) ✓ DELETE nuevo1 (admin alan) ## responsable obligatorio y resumen ✓ crear sin responsable → 400 ✓ crear con ids (y 'Jesús' con acento → jesus) ✓ texto libre → se acepta con aviso ✓ lista como array también vale ✓ PATCH responsable vacío → 400 ✓ PATCH sin tocar responsable sigue funcionando ✓ filtro por id ✓ filtro con acento ✓ GET tareas trae el mapa equipo ✓ resumen por_responsable (jesus) ✓ resumen por_responsable cuenta abiertos ✓ resumen conserva por_pista RESULTADO: 57 correctas · 0 fallidas · datos en ``` | Área | Probado | |---|---| | siembra | con un pendiente viejo sin `responsable` ni `responsable_ids`: la primera corrida crea los 9 miembros y 12 pendientes (el viejo se respeta), completa el responsable vacío a `leo` con historial y recalcula `responsable_ids`; la segunda corrida no crea ni cambia nada | | equipo | GET para cualquiera con `tiene_login` (derivado del htpasswd), `es_admin` (de `ACTAS_ADMINS`) y pendientes por miembro; `logins_sin_miembro` solo para admin; POST/PATCH 403 para no admin; 409 duplicado; 400 área inválida; PATCH con historial; `activo:false` oculta sin borrar (`?todos=1` lo muestra); 404 | | accesos | POST 403 no admin; 400 contraseña corta y usuario inválido; alta sobre miembro existente (`nuevo_miembro:false`) y alta de usuario+miembro nuevos; línea `$apr1$` verificada con `apr1()`; permisos 640 conservados; 409 duplicado; `GET /api/usuarios` igual que antes; la cuenta nueva cambia su contraseña por `/api/password`; bitácora `_accesos.csv`; DELETE 403 no admin, 400 a sí mismo, 404 inexistente, **409 último administrador con acceso**, ok con dos admins; miembro queda `activo:false` | | pendientes | crear sin responsable → 400; `"Michelle, Jesús"` → `["michelle","jesus"]`; texto libre aceptado con `aviso`; lista como array; PATCH con responsable vacío → 400; PATCH sin tocar responsable sigue igual; filtro por id y con acento; `GET /api/tareas` trae `equipo`; `resumen.por_responsable` con nombre y abiertos; `por_pista` se conserva | `backend/tests-1013.sh` se volvió a correr contra este backend (61/61) tras ajustar sus altas de pendientes a la regla nueva (responsable obligatorio) y el conteo de la siembra (13 pendientes). ## 2 · Páginas — Chromium headless (Playwright), teléfono y escritorio | Página | Probado | Resultado | |---|---|---| | `tableros/equipo.html` (alan) | ve la lista de miembros sin ningún botón ni «Nuevo usuario»; toca «Jesús» y ve sus 2 pendientes con enlace al tablero filtrado | ✓ | | `tableros/kanban.html` (alan) | las tarjetas muestran el **nombre** («Michelle Márquez», no `michelle`); crear sin responsable → mensaje de validación y no se envía; con dos chips (Adriana, Alán) se crea y la tarjeta muestra ambos nombres; `?responsable=adriana` filtra por id | ✓ | | `tableros/equipo.html` (leo) | «Nuevo usuario / miembro» con «crear acceso» marcado y contraseña generada → se muestra **una sola vez**; la fila nueva dice acceso «sí»; el hash del htpasswd valida con `apr1()`; «Quitar acceso» → acceso «no» e inactivo; «Editar» guarda el correo; leo no tiene botón para quitarse el acceso | ✓ | | `tableros/produccion.html` / `ingenieria.html` | los bloqueos y las tarjetas muestran el nombre del responsable | ✓ | | suite del 13-oct (`test_kanban.py`) | repetida con la regla nueva (elige un chip al crear): drag&drop, Mover a…, historial, borrar admin, plan | ✓ sin errores de consola | ## 3 · Sitio estático `mkdocs build --strict` sobre una copia: las mismas 55 advertencias preexistentes (PDF/binarios ausentes en la copia); ninguna sobre `tableros/equipo.html` ni los archivos tocados. Referencias `src`/`href` de `equipo.html`, `kanban.html`, `ingenieria.html`, `produccion.html`, `admin.html`, `cuenta.html`: 0 rotas. `node --check tableros/kanban.js`: sin errores.