From e407e5c6269a1828aa29106e5597c8801fe68618 Mon Sep 17 00:00:00 2001 From: alexandrump Date: Thu, 29 Oct 2026 20:53:20 +0000 Subject: [PATCH] feat: soporte dias propuestos (param d) en formulario de invitados --- server.py | 63 +++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 59 insertions(+), 4 deletions(-) diff --git a/server.py b/server.py index 35137d7..6c39c09 100644 --- a/server.py +++ b/server.py @@ -142,6 +142,27 @@ def invitado(n, f): return (n, ts) if -10 <= delta <= 14 else None +def parse_dias(d_str): + """Valida una lista de timestamps separados por comas. Devuelve lista de ints o None.""" + if not d_str: + return None + parts = str(d_str).replace(' ', '').split(',') + if not 1 <= len(parts) <= 10: + return None + today = datetime.date.today() + result = [] + for p in parts: + try: + ts = int(p) + day = datetime.datetime.fromtimestamp(ts, datetime.timezone.utc).date() + if not (-1 <= (day - today).days <= 60): + return None + result.append(ts) + except (ValueError, OverflowError, OSError): + return None + return result if result else None + + class H(BaseHTTPRequestHandler): server_version = 'aqnsn' @@ -166,8 +187,22 @@ class H(BaseHTTPRequestHandler): if limited(check_hits, self.client_ip(), 40): return self.reply(429, {'ok': False}) q = parse_qs(urlparse(self.path).query) - inv = invitado(q.get('n', [''])[0], q.get('f', [''])[0]) - return self.reply(200, {'ok': True, 'nombre': inv[0], 'cita': inv[1]} if inv else {'ok': False}) + n_raw = q.get('n', [''])[0] + f_raw = q.get('f', [''])[0] + d_raw = q.get('d', [''])[0] + if f_raw: + inv = invitado(n_raw, f_raw) + return self.reply(200, {'ok': True, 'nombre': inv[0], 'cita': inv[1]} if inv else {'ok': False}) + if d_raw: + n = ' '.join(str(n_raw or '').split()) + if not n or not NAME_RE.match(n): + return self.reply(200, {'ok': False}) + dias = parse_dias(d_raw) + if not dias: + return self.reply(200, {'ok': False}) + return self.reply(200, {'ok': True, 'nombre': n, + 'dias': [{'ts': ts, 'txt': cita_txt(ts)} for ts in dias]}) + return self.reply(200, {'ok': False}) def invitados(self): try: @@ -181,8 +216,28 @@ class H(BaseHTTPRequestHandler): return self.reply(200, {'ok': True}) # trampa o demasiado rápido: no se envía if limited(guest_hits, self.client_ip(), 8): return self.reply(429, {'ok': False, 'error': 'Demasiados envíos. Inténtalo más tarde.'}) - inv = invitado(d.get('n'), d.get('f')) - nombre, ts = inv if inv else (None, None) + f_raw = str(d.get('f') or '').strip() + d_raw = str(d.get('d') or '').strip() + dia_raw = str(d.get('dia') or '').strip() + if f_raw: + inv = invitado(d.get('n'), f_raw) + nombre, ts = inv if inv else (None, None) + elif d_raw and dia_raw: + n_val = ' '.join(str(d.get('n') or '').split()) + if not n_val or not NAME_RE.match(n_val): + nombre, ts = None, None + else: + dias = parse_dias(d_raw) + try: + dia_ts = int(dia_raw) + except (ValueError, TypeError): + dia_ts = None + if dias and dia_ts is not None and dia_ts in dias: + nombre, ts = n_val, dia_ts + else: + nombre, ts = None, None + else: + nombre, ts = None, None if not nombre: return self.reply(403, {'ok': False, 'error': 'Enlace no válido o caducado.'}) if d.get('consent') is not True: