Pedido de Leo (28-oct, 18:00): Michelle comenta antes de mover y luego tenía que escribir lo mismo otra vez. El «¿por qué?» lista tus últimos comentarios del pendiente; si comentaste después del último cambio de columna, ya viene elegido. PATCH /api/tarea acepta _nota_de (el «cuando» de un comentario tuyo; 400 si no existe o es de otra persona): la entrada guarda «ref», no repite el texto en el hilo y lleva un extracto para la Actividad. En el hilo, el comentario elegido lleva «→ Hecho»; un porqué pegado igual que un comentario anterior también se ve una sola vez. «Comentar» revisa el texto al hacer clic. Pruebas: tests-comentarios.sh (26) y las demás; caso de Michelle en el navegador. DESPLIEGUE A14; lote 2026-10-28_comentarios-elegir. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013SfRSvDd335NPYEbBrDFGE
73 lines
6.4 KiB
Bash
73 lines
6.4 KiB
Bash
#!/usr/bin/env bash
|
|
# Pruebas del 28-oct (Leo): comentarios en los pendientes y el «¿por qué?» al moverlos. PATCH /api/tarea con «_nota»:
|
|
# solo el comentario (cualquiera con sesión, aunque no sea el campeón) o junto con el cambio de columna (solo el campeón).
|
|
# La nota queda en el historial en «cambio» (como siempre, para la Actividad) y aparte en «nota» (el hilo del detalle).
|
|
# Arranca app.py con datos temporales; no toca el servidor.
|
|
# Uso: bash backend/tests-comentarios.sh <ruta-a-hbox-docs> [puerto]
|
|
set -u
|
|
REPO=${1:?ruta a hbox-docs}; PORT=${2:-8095}
|
|
T=$(mktemp -d); export ACTAS_DIR=$T/actas HTPASSWD_FILE=$T/htpasswd HTPASSWD_LOCK=$T/.lock ACTAS_ADMINS=leo PORT
|
|
mkdir -p $ACTAS_DIR $T/equipo $T/tareas; : > $T/htpasswd
|
|
for u in leo adriana jesus michelle claude; do
|
|
echo "{\"id\":\"$u\",\"nombre\":\"$u\",\"area\":\"ingenieria\",\"activo\":true}" > $T/equipo/$u.json
|
|
done
|
|
echo '{"id":"t-a","titulo":"Cotizar gabinetes","responsable":"adriana, jesus","campeon":"adriana","estado":"en-curso","pista":"compras","sitios":["qro"],"orden":0,"historial":[]}' > $T/tareas/t-a.json
|
|
echo '{"id":"t-m","titulo":"v6 bloque E","responsable":"michelle","campeon":"michelle","estado":"en-curso","pista":"ingenieria","sitios":["qro"],"orden":1,"historial":[]}' > $T/tareas/t-m.json
|
|
python3 $REPO/backend/app.py > $T/app.log 2>&1 &
|
|
APP=$!; trap "kill $APP 2>/dev/null" EXIT; sleep 1.8
|
|
U="http://127.0.0.1:$PORT"
|
|
ok=0; fail=0
|
|
check() { if [[ "$3" == *"$2"* ]]; then ok=$((ok+1)); echo " ✓ $1"; else fail=$((fail+1)); echo " ✕ $1 — esperaba «$2», obtuve: ${3:0:220}"; fi; }
|
|
as() { curl -s -H "X-Remote-User: $1" -H "Content-Type: application/json" "${@:2}"; }
|
|
ultimo() { python3 -c "import json,sys; d=json.load(sys.stdin); h=d['tarea']['historial'][-1]; print(json.dumps(h, ensure_ascii=False))"; }
|
|
|
|
echo "## comentar"
|
|
R=$(as michelle -X PATCH -d '{"_nota":"Ya pedí la cotización a dos proveedores."}' "$U/api/tarea?id=t-a")
|
|
check "quien no es campeón comenta" '"ok":true' "$R"
|
|
check "el comentario queda en «nota»" '"nota": "Ya pedí la cotización a dos proveedores."' "$(echo "$R" | ultimo)"
|
|
check "y en «cambio» (para la Actividad)" '"cambio": "Ya pedí la cotización a dos proveedores."' "$(echo "$R" | ultimo)"
|
|
check "con su autor" '"quien": "michelle"' "$(echo "$R" | ultimo)"
|
|
check "comentar no mueve la columna" '"estado":"en-curso"' "$R"
|
|
LARGO=$(python3 -c "print('x'*1200)")
|
|
R=$(as michelle -X PATCH -d "{\"_nota\":\"$LARGO\"}" "$U/api/tarea?id=t-a")
|
|
check "un comentario largo se recorta a 1000" "1000" "$(echo "$R" | python3 -c "import json,sys; print(len(json.load(sys.stdin)['tarea']['historial'][-1]['nota']))")"
|
|
check "sin sesión no se comenta" '"ok":false' "$(curl -s -H 'Content-Type: application/json' -X PATCH -d '{"_nota":"hola"}' "$U/api/tarea?id=t-a")"
|
|
check "un comentario vacío no deja rastro" '"sin_cambios":true' "$(as michelle -X PATCH -d '{"_nota":" "}' "$U/api/tarea?id=t-a")"
|
|
|
|
echo "## mover con su porqué"
|
|
check "quien no es campeón no mueve, aunque traiga porqué" 'campe' "$(as michelle -X PATCH -d '{"estado":"hecho","_nota":"listo"}' "$U/api/tarea?id=t-a")"
|
|
R=$(as adriana -X PATCH -d '{"estado":"hecho","_nota":"Evidencia: cotización COT-123 en el cotizador."}' "$U/api/tarea?id=t-a")
|
|
check "el campeón mueve a Hecho con la evidencia" '"estado":"hecho"' "$R"
|
|
check "el historial dice el cambio y la nota" 'estado: en-curso → hecho — Evidencia: cotización COT-123' "$(echo "$R" | ultimo)"
|
|
check "y la nota sola en «nota»" '"nota": "Evidencia: cotización COT-123 en el cotizador."' "$(echo "$R" | ultimo)"
|
|
R=$(as adriana -X PATCH -d '{"estado":"en-curso","_nota":"Faltó la firma del proveedor."}' "$U/api/tarea?id=t-a")
|
|
check "reabrir con lo que faltó" 'estado: hecho → en-curso — Faltó la firma del proveedor.' "$(echo "$R" | ultimo)"
|
|
R=$(as adriana -X PATCH -d '{"estado":"bloqueado"}' "$U/api/tarea?id=t-a")
|
|
check "mover sin nota sigue funcionando (lotes, standup)" '"estado":"bloqueado"' "$R"
|
|
check "y sin nota no hay «nota»" 'None' "$(echo "$R" | python3 -c "import json,sys; print(json.load(sys.stdin)['tarea']['historial'][-1].get('nota'))")"
|
|
|
|
echo "## elegir uno de sus comentarios como el porqué (28-oct)"
|
|
R=$(as michelle -X PATCH -d '{"_nota":"D12 quedó a 3.44 mm de U7.1 (se pedían 2 mm); L2 a 5 mm."}' "$U/api/tarea?id=t-m")
|
|
CUANDO=$(echo "$R" | python3 -c "import json,sys; print(json.load(sys.stdin)['tarea']['historial'][-1]['cuando'])")
|
|
sleep 1.1; as jesus -X PATCH -d '{"_nota":"Comentario de Jesús en el mismo pendiente."}' "$U/api/tarea?id=t-m" > /dev/null
|
|
OTRO=$(as leo "$U/api/tareas" | python3 -c "import json,sys; t=[x for x in json.load(sys.stdin)['tareas'] if x['id']=='t-m'][0]; print(t['historial'][-1]['cuando'])")
|
|
check "con el comentario de otra persona no" 'comentario tuyo' "$(as michelle -X PATCH -d "{\"estado\":\"hecho\",\"_nota_de\":\"$OTRO\"}" "$U/api/tarea?id=t-m")"
|
|
check "con un comentario que no existe no" 'comentario tuyo' "$(as michelle -X PATCH -d '{"estado":"hecho","_nota_de":"2020-01-01T00:00:00"}' "$U/api/tarea?id=t-m")"
|
|
check "…y no se movió" '"estado": "en-curso"' "$(as leo "$U/api/tareas" | python3 -c "import json,sys; t=[x for x in json.load(sys.stdin)['tareas'] if x['id']=='t-m'][0]; print(json.dumps({'estado': t['estado']}))")"
|
|
R=$(as michelle -X PATCH -d "{\"estado\":\"hecho\",\"_nota_de\":\"$CUANDO\"}" "$U/api/tarea?id=t-m")
|
|
check "con su propio comentario se mueve" '"estado":"hecho"' "$R"
|
|
check "la entrada guarda «ref» con su «cuando»" "\"ref\": \"$CUANDO\"" "$(echo "$R" | ultimo)"
|
|
check "y no repite el texto como comentario (sin «nota»)" 'None' "$(echo "$R" | python3 -c "import json,sys; print(json.load(sys.stdin)['tarea']['historial'][-1].get('nota'))")"
|
|
check "la Actividad lleva el extracto" 'por su comentario del' "$(echo "$R" | ultimo)"
|
|
R=$(as michelle -X PATCH -d "{\"estado\":\"en-curso\",\"_nota_de\":\"$CUANDO\",\"_nota\":\"Leo pidió revisar L2 otra vez.\"}" "$U/api/tarea?id=t-m")
|
|
check "citar y además escribir: guarda las dos cosas" '"nota": "Leo pidió revisar L2 otra vez."' "$(echo "$R" | ultimo)"
|
|
check "…con su «ref»" "\"ref\": \"$CUANDO\"" "$(echo "$R" | ultimo)"
|
|
check "citar sin cambiar nada no deja rastro" '"sin_cambios":true' "$(as michelle -X PATCH -d "{\"_nota_de\":\"$CUANDO\"}" "$U/api/tarea?id=t-m")"
|
|
|
|
echo "## la Actividad sigue leyendo el historial"
|
|
check "la Actividad muestra el comentario" 'a dos proveedores' "$(as leo "$U/api/actividad?dias=2")"
|
|
|
|
echo
|
|
echo "RESULTADO: $ok correctas · $fail fallidas · datos en $T"
|
|
[ $fail -eq 0 ]
|