- Rol «externas» para la asamblea de externas: pide sin cupo, siempre con el colectivo de fuera y su contacto, y sus solicitudes salen en naranja hasta que la asamblea de la Enre las confirma. - /pedir/ explica en una línea que los colectivos externos piden fecha en la asamblea de externas, los lunes de 19:00 a 20:00. - Seguridad: argon2 limitado a dos cálculos a la vez y el intento se cuenta antes de calcular (60 accesos simultáneos llevaban el proceso a 3,8 GB); bloqueo por cuenta a 20 fallos para que no se pueda dejar fuera a la asamblea; avisos por sesión en vez de por URL; sig sin «..»; eventos de 31 días como mucho; parámetros de argon2 acotados. - Títulos pegados arriba en todas las páginas; la franja de la enredadera recupera ese alto para seguir llenando la pantalla. - despliegue/: instalar.sh, cuenta.sh, servicio de systemd con el proceso encerrado, fragmento de nginx que además deja de servir .git y las notas internas, y configuración de ejemplo. Ninguna contraseña en el repositorio.
276 lines
9.3 KiB
Go
276 lines
9.3 KiB
Go
package main
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
const hoy = Dia("2026-09-22") // martes
|
|
|
|
func solicitud(usuario string, desde, hasta Dia) Solicitud {
|
|
return Solicitud{
|
|
Solicitante: usuario,
|
|
Rol: RolInterno,
|
|
Titulo: "Concierto de prueba",
|
|
Desde: desde,
|
|
Hasta: hasta,
|
|
Hora: "20:00",
|
|
}
|
|
}
|
|
|
|
func evento(id, usuario string, desde, hasta Dia, estado Estado) Evento {
|
|
return Evento{
|
|
ID: id,
|
|
Titulo: "Evento " + id,
|
|
Solicitante: usuario,
|
|
Desde: desde,
|
|
Hasta: hasta,
|
|
Estado: estado,
|
|
Creado: hoy.MustTime(),
|
|
}
|
|
}
|
|
|
|
func TestVentanaTresMeses(t *testing.T) {
|
|
rg := ReglasPorDefecto()
|
|
|
|
// 2026-10-02 es viernes, dentro de los tres meses.
|
|
if err := rg.Validar(solicitud("hacklab", "2026-10-02", "2026-10-02"), nil, hoy); err != nil {
|
|
t.Fatalf("una fecha dentro de la ventana deberia valer: %v", err)
|
|
}
|
|
// 2027-01-01 es viernes y cae fuera: hoy + 3 meses es 2026-12-22.
|
|
err := rg.Validar(solicitud("hacklab", "2027-01-01", "2027-01-01"), nil, hoy)
|
|
if err == nil || !strings.Contains(err.Error(), "3 meses") {
|
|
t.Fatalf("una fecha a mas de 3 meses tiene que fallar por la ventana, dio: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestAntelacionMinima(t *testing.T) {
|
|
rg := ReglasPorDefecto()
|
|
// 2026-09-25 es el viernes de esta semana: a 3 dias, caducaria al instante.
|
|
err := rg.Validar(solicitud("hacklab", "2026-09-25", "2026-09-25"), nil, hoy)
|
|
if err == nil || !strings.Contains(err.Error(), "antelación") {
|
|
t.Fatalf("pedir con menos de 7 dias tiene que fallar, dio: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestCupoTresDiasEnLaVentana(t *testing.T) {
|
|
rg := ReglasPorDefecto()
|
|
|
|
// Tres dias ya cogidos por el mismo colectivo: uno confirmado, dos solicitados.
|
|
eventos := []Evento{
|
|
evento("a", "hacklab", "2026-10-02", "2026-10-02", Confirmado),
|
|
evento("b", "hacklab", "2026-10-10", "2026-10-11", Solicitado),
|
|
}
|
|
|
|
err := rg.Validar(solicitud("hacklab", "2026-10-16", "2026-10-16"), eventos, hoy)
|
|
if err == nil || !strings.Contains(err.Error(), "cupo") {
|
|
t.Fatalf("el cuarto dia tiene que fallar por cupo, dio: %v", err)
|
|
}
|
|
// El cupo es por colectivo: otro colectivo si puede coger ese dia.
|
|
if err := rg.Validar(solicitud("feminismos", "2026-10-16", "2026-10-16"), eventos, hoy); err != nil {
|
|
t.Fatalf("otro colectivo no deberia arrastrar el cupo del primero: %v", err)
|
|
}
|
|
// Los dias rechazados o caducados no cuentan.
|
|
eventos[1].Estado = Caducado
|
|
if err := rg.Validar(solicitud("hacklab", "2026-10-16", "2026-10-17"), eventos, hoy); err != nil {
|
|
t.Fatalf("un evento caducado no deberia gastar cupo: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestCupoNoCuentaFechasPasadas(t *testing.T) {
|
|
rg := ReglasPorDefecto()
|
|
viejos := []Evento{evento("v", "hacklab", "2026-08-07", "2026-08-09", Confirmado)}
|
|
if err := rg.Validar(solicitud("hacklab", "2026-10-02", "2026-10-04"), viejos, hoy); err != nil {
|
|
t.Fatalf("lo que ya paso no gasta cupo: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestSinSolapes(t *testing.T) {
|
|
rg := ReglasPorDefecto()
|
|
eventos := []Evento{evento("a", "hacklab", "2026-10-03", "2026-10-03", Solicitado)}
|
|
|
|
err := rg.Validar(solicitud("feminismos", "2026-10-02", "2026-10-04"), eventos, hoy)
|
|
if err == nil || !strings.Contains(err.Error(), "ya está cogido") {
|
|
t.Fatalf("un dia solicitado por otro tiene que bloquear, dio: %v", err)
|
|
}
|
|
// Al caducar se libera la fecha.
|
|
eventos[0].Estado = Caducado
|
|
if err := rg.Validar(solicitud("feminismos", "2026-10-02", "2026-10-04"), eventos, hoy); err != nil {
|
|
t.Fatalf("una fecha caducada tiene que quedar libre: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestSoloFindesSalvoLaEnre(t *testing.T) {
|
|
rg := ReglasPorDefecto()
|
|
// 2026-10-06 es martes.
|
|
err := rg.Validar(solicitud("hacklab", "2026-10-06", "2026-10-06"), nil, hoy)
|
|
if err == nil || !strings.Contains(err.Error(), "no es día reservable") {
|
|
t.Fatalf("un martes no es reservable para un colectivo, dio: %v", err)
|
|
}
|
|
s := solicitud("enre", "2026-10-06", "2026-10-06")
|
|
s.Rol = RolEnre
|
|
if err := rg.Validar(s, nil, hoy); err != nil {
|
|
t.Fatalf("la enre si puede poner cualquier dia: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestLaEnreNoTieneCupoNiVentana(t *testing.T) {
|
|
rg := ReglasPorDefecto()
|
|
eventos := []Evento{
|
|
evento("a", "enre", "2026-10-02", "2026-10-04", Confirmado),
|
|
evento("b", "enre", "2026-10-09", "2026-10-11", Confirmado),
|
|
}
|
|
s := solicitud("enre", "2027-06-04", "2027-06-06")
|
|
s.Rol = RolEnre
|
|
if err := rg.Validar(s, eventos, hoy); err != nil {
|
|
t.Fatalf("la enre no deberia topar con cupo ni ventana: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestAmadrinadoPideContacto(t *testing.T) {
|
|
rg := ReglasPorDefecto()
|
|
s := solicitud("hacklab", "2026-10-02", "2026-10-02")
|
|
s.Amadrinado = "Colectivo de fuera"
|
|
err := rg.Validar(s, nil, hoy)
|
|
if err == nil || !strings.Contains(err.Error(), "contacto") {
|
|
t.Fatalf("amadrinar sin contacto tiene que fallar, dio: %v", err)
|
|
}
|
|
s.Contacto = "fuera@riseup.net"
|
|
if err := rg.Validar(s, nil, hoy); err != nil {
|
|
t.Fatalf("con contacto deberia valer: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestCaducidad(t *testing.T) {
|
|
rg := ReglasPorDefecto()
|
|
ahora := hoy.MustTime()
|
|
|
|
cerca := evento("a", "hacklab", "2026-09-27", "2026-09-27", Solicitado)
|
|
if m := rg.Caducidad(cerca, ahora); m == "" || !strings.Contains(m, "menos de 7") {
|
|
t.Fatalf("a 5 dias sin confirmar tiene que caducar, dio %q", m)
|
|
}
|
|
|
|
lejos := evento("b", "hacklab", "2026-11-06", "2026-11-06", Solicitado)
|
|
if m := rg.Caducidad(lejos, ahora); m != "" {
|
|
t.Fatalf("una solicitud reciente y lejana no caduca, dio %q", m)
|
|
}
|
|
|
|
vieja := lejos
|
|
vieja.Creado = ahora.AddDate(0, 0, -31)
|
|
if m := rg.Caducidad(vieja, ahora); m == "" || !strings.Contains(m, "esperando") {
|
|
t.Fatalf("31 dias esperando tiene que caducar, dio %q", m)
|
|
}
|
|
|
|
confirmada := cerca
|
|
confirmada.Estado = Confirmado
|
|
if m := rg.Caducidad(confirmada, ahora); m != "" {
|
|
t.Fatalf("un evento confirmado no caduca nunca, dio %q", m)
|
|
}
|
|
}
|
|
|
|
func TestTurnoDeFinde(t *testing.T) {
|
|
rg := ReglasPorDefecto() // ancla 2026-09-25, turno ruido
|
|
|
|
casos := []struct {
|
|
dia Dia
|
|
quer Turno
|
|
}{
|
|
{"2026-09-25", Ruido}, // viernes ancla
|
|
{"2026-09-26", Ruido}, // sabado del mismo finde
|
|
{"2026-09-27", Ruido}, // domingo del mismo finde
|
|
{"2026-10-02", Tranqui}, // finde siguiente
|
|
{"2026-10-09", Ruido},
|
|
{"2026-10-16", Tranqui},
|
|
{"2026-09-18", Tranqui}, // hacia atras tambien alterna
|
|
}
|
|
for _, c := range casos {
|
|
if got := rg.TurnoDe(c.dia, nil); got != c.quer {
|
|
t.Errorf("%s: turno %q, esperaba %q", c.dia, got, c.quer)
|
|
}
|
|
}
|
|
|
|
// Un dia de entre semana no tiene turno.
|
|
if got := rg.TurnoDe("2026-10-06", nil); got != "" {
|
|
t.Errorf("un martes no tiene turno de finde, dio %q", got)
|
|
}
|
|
|
|
// La excepcion escrita a mano manda sobre la alternancia.
|
|
exc := map[Dia]Turno{"2026-10-02": Ruido}
|
|
if got := rg.TurnoDe("2026-10-03", exc); got != Ruido {
|
|
t.Errorf("la excepcion del viernes tiene que valer para todo el finde, dio %q", got)
|
|
}
|
|
}
|
|
|
|
func TestRangoYDiaISO(t *testing.T) {
|
|
dias := Rango("2026-10-02", "2026-10-04")
|
|
if len(dias) != 3 || dias[0] != "2026-10-02" || dias[2] != "2026-10-04" {
|
|
t.Fatalf("rango mal calculado: %v", dias)
|
|
}
|
|
if Rango("2026-10-04", "2026-10-02") != nil {
|
|
t.Fatal("un rango invertido tiene que dar nada")
|
|
}
|
|
if got := Dia("2026-10-02").DiaISO(); got != 5 {
|
|
t.Fatalf("2026-10-02 es viernes, iso 5, dio %d", got)
|
|
}
|
|
if got := ViernesDe("2026-10-04"); got != "2026-10-02" {
|
|
t.Fatalf("el viernes del domingo 4 es el 2, dio %q", got)
|
|
}
|
|
}
|
|
|
|
func TestVentanaDevuelveTresMeses(t *testing.T) {
|
|
rg := ReglasPorDefecto()
|
|
primero, ultimo := rg.Ventana(hoy)
|
|
if primero != "2026-09-29" {
|
|
t.Errorf("primera fecha pedible %q, esperaba 2026-09-29", primero)
|
|
}
|
|
if ultimo != "2026-12-22" {
|
|
t.Errorf("ultima fecha pedible %q, esperaba 2026-12-22", ultimo)
|
|
}
|
|
}
|
|
|
|
func TestModificarNoChocaConsigoMismo(t *testing.T) {
|
|
rg := ReglasPorDefecto()
|
|
eventos := []Evento{
|
|
evento("a", "hacklab", "2026-10-02", "2026-10-03", Confirmado),
|
|
evento("b", "vivienda", "2026-10-09", "2026-10-09", Solicitado),
|
|
}
|
|
|
|
// La asamblea mueve la hora del evento «a» sin cambiarle los días.
|
|
s := solicitud("hacklab", "2026-10-02", "2026-10-03")
|
|
s.Rol, s.Excluir = RolEnre, "a"
|
|
if err := rg.Validar(s, eventos, hoy); err != nil {
|
|
t.Fatalf("modificar un evento en sus propios días deberia valer: %v", err)
|
|
}
|
|
|
|
// Pero no puede llevarlo encima del evento «b».
|
|
s.Desde, s.Hasta = "2026-10-09", "2026-10-09"
|
|
if err := rg.Validar(s, eventos, hoy); err == nil || !strings.Contains(err.Error(), "cogido") {
|
|
t.Fatalf("mover «a» encima de «b» deberia fallar por solape, dio %v", err)
|
|
}
|
|
}
|
|
|
|
func TestExternasSinCupoPeroConColectivo(t *testing.T) {
|
|
rg := ReglasPorDefecto()
|
|
eventos := []Evento{
|
|
evento("a", "externas", "2026-10-02", "2026-10-04", Solicitado),
|
|
evento("b", "externas", "2026-10-09", "2026-10-11", Solicitado),
|
|
}
|
|
|
|
s := solicitud("externas", "2026-10-16", "2026-10-16")
|
|
s.Rol = RolExternas
|
|
if err := rg.Validar(s, eventos, hoy); err == nil || !strings.Contains(err.Error(), "colectivo de fuera") {
|
|
t.Fatalf("sin decir de qué colectivo es deberia fallar, dio %v", err)
|
|
}
|
|
|
|
// Con seis días ya apuntados, un séptimo vale: externas no tiene cupo.
|
|
s.Amadrinado, s.Contacto = "Colectivo Sin Techo", "sintecho@example.org"
|
|
if err := rg.Validar(s, eventos, hoy); err != nil {
|
|
t.Fatalf("externas no deberia tener cupo: %v", err)
|
|
}
|
|
|
|
// Pero sigue sin poder pedir entre semana.
|
|
s.Desde, s.Hasta = "2026-10-14", "2026-10-14"
|
|
if err := rg.Validar(s, eventos, hoy); err == nil {
|
|
t.Fatal("externas no deberia poder pedir un miércoles")
|
|
}
|
|
}
|