Files
fn_registry/python/functions/infra/dav_make_calendar.md
T
egutierrez 1c8a86594f feat(dav): expand_rrule + dav_make_calendar para recurrencia y multi-calendario
Dos funciones nuevas del grupo de capacidad `dav`:
- expand_rrule_py_infra (pure): expande una RRULE iCalendar a las fechas de
  cada ocurrencia dentro de un rango [from, to]. Solo stdlib (datetime, re).
  Soporta FREQ DAILY/WEEKLY/MONTHLY/YEARLY, INTERVAL, COUNT, UNTIL, BYDAY. 9 tests.
- dav_make_calendar_py_infra (impure): crea una coleccion de calendario nueva
  via MKCALENDAR + PROPPATCH de nombre/color. Idempotente si ya existe. 11 tests.

Consumidas por la app osint_web (eventos recurrentes + creacion de agendas).
Pagina del grupo dav actualizada con ambas.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-12 23:30:01 +02:00

5.6 KiB

name, kind, lang, domain, version, purity, signature, description, tags, uses_functions, uses_types, returns, returns_optional, error_type, imports, params, output, tested, tests, test_file_path, file_path
name kind lang domain version purity signature description tags uses_functions uses_types returns returns_optional error_type imports params output tested tests test_file_path file_path
dav_make_calendar function py infra 1.0.0 impure def dav_make_calendar(base_url: str, username: str, password: str, calendar_home: str, slug: str, display_name: str = "", color: str = "", description: str = "", *, timeout_s: float = 20.0, verify_tls: bool = True) -> dict Crea una nueva coleccion de calendario CalDAV (una agenda nueva) bajo el calendar-home de un principal via MKCALENDAR, fijando el displayname en el cuerpo, y opcionalmente fija color (Apple calendar-color) y descripcion (CalDAV calendar-description) con un PROPPATCH posterior. La coleccion se crea en <calendar_home><slug>/. El slug se sanea a [a-z0-9_-] (minusculas, espacios->guion); si queda vacio devuelve error de validacion. Idempotente: 201 Created es exito; 405/301 (ya existe) devuelve {status:'ok', existed:True}. Escapa display_name/description para XML. Construye Authorization: Basic base64(user:pass) a mano. Maneja errores sin lanzar (salvo validacion de args). Solo stdlib (urllib, base64, re, ssl, xml.sax.saxutils). Probado contra Xandikos.
dav
caldav
calendar
mkcalendar
proppatch
create
collection
color
http
infra
false
base64
re
ssl
urllib.error
urllib.request
xml.sax.saxutils
name desc
base_url URL base del servidor DAV sin barra final (p.ej. 'https://dav-eedeb681c4ab89ab8e444ac9.organic-machine.com').
name desc
username usuario para HTTP Basic auth (p.ej. 'enmanuel').
name desc
password contrasena para HTTP Basic auth. Resolver desde pass con pass_get_secret, nunca hardcodear.
name desc
calendar_home ruta del calendar-home del principal con barra final (p.ej. '/enmanuel/calendars/'). La nueva coleccion cuelga de el.
name desc
slug segmento de path de la coleccion en la URL (p.ej. 'trabajo'); se sanea a [a-z0-9_-]. La coleccion se crea en <calendar_home><slug>/. Si queda vacio tras sanear, devuelve error de validacion.
name desc
display_name nombre visible de la coleccion (DAV:displayname). Si vacio, usa el slug saneado.
name desc
color color de la coleccion como hex '#rrggbb' (propiedad calendar-color de Apple, http://apple.com/ns/ical/). Opcional; '' lo omite.
name desc
description descripcion de la coleccion (calendar-description de CalDAV). Opcional; '' lo omite.
name desc
timeout_s timeout de cada peticion HTTP en segundos. Default 20.0.
name desc
verify_tls si True (default) verifica el certificado TLS. No desactivar salvo entorno de prueba.
dict. En exito: {status:'ok', http_status:int, href:str} y, si la coleccion ya existia, ademas existed:True. En error (sin lanzar): {status:'error', http_status:int|None, href:str, error:str}. href es la ruta de la coleccion (calendar_home + slug saneado + '/'). true
test_sanitize_slug_minusculas
test_sanitize_slug_espacios_a_guion
test_sanitize_slug_elimina_caracteres_raros
test_sanitize_slug_colapsa_guiones_y_recorta
test_sanitize_slug_vacio
test_join_url_compone_la_coleccion
test_mkcalendar_xml_incluye_displayname
test_mkcalendar_xml_escapa_displayname
test_proppatch_xml_color_y_descripcion
test_proppatch_xml_solo_color
test_proppatch_xml_escapa_descripcion
python/functions/infra/dav_make_calendar_test.py python/functions/infra/dav_make_calendar.py

Ejemplo

import sys
sys.path.insert(0, "python/functions")
from infra.pass_get_secret import pass_get_secret
from infra.dav_make_calendar import dav_make_calendar

pw = pass_get_secret("dav/xandikos-enmanuel")["value"]  # NO logear

res = dav_make_calendar(
    base_url="https://dav-eedeb681c4ab89ab8e444ac9.organic-machine.com",
    username="enmanuel",
    password=pw,
    calendar_home="/enmanuel/calendars/",
    slug="trabajo",
    display_name="Trabajo",
    color="#e8590c",
)
print(res)
# {'status': 'ok', 'http_status': 201, 'href': '/enmanuel/calendars/trabajo/'}
# Volver a llamar con el mismo slug:
# {'status': 'ok', 'http_status': 405, 'href': '/enmanuel/calendars/trabajo/', 'existed': True}

Cuando usarla

Cuando el usuario quiere anadir una agenda/calendario nuevo ademas del principal: una coleccion CalDAV separada ("Trabajo", "Personal", "Cumpleanos") con su propio nombre visible y color, bajo el calendar-home del principal. El href devuelto es lo que luego pasas como collection_path a caldav_put_event para crear eventos en esa agenda, o a dav_list_calendars para verla en el selector.

Gotchas

  • Impura: requiere red + Basic auth contra el servidor DAV. El password viene de pass, no se logea ni se hardcodea.
  • Idempotente: si la coleccion ya existe en ese path el servidor responde 405 (Method Not Allowed) o 301; ambos se traducen a {status:'ok', existed:True} en vez de error, asi que es seguro reintentar.
  • El PROPPATCH de color usa el calendar-color de Apple (http://apple.com/ns/ical/). Servidores que no lo soporten pueden ignorarlo: el fallo del PROPPATCH NO es fatal (el calendario ya quedo creado) y se ignora silenciosamente; el color simplemente no se aplica. Si necesitas confirmar el color, leelo despues con dav_list_calendars.
  • El slug se sanea a [a-z0-9_-] (minusculas, espacios->guion, resto fuera). Un slug que queda vacio tras sanear (p.ej. solo simbolos) devuelve error de validacion sin tocar la red. El display_name y la description se escapan para XML, pero el slug que va en la URL ya esta restringido al charset seguro.