feat(browser): auto-commit con 178 cambios
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,105 @@
|
||||
---
|
||||
name: add_event_dav
|
||||
kind: pipeline
|
||||
lang: py
|
||||
domain: pipelines
|
||||
version: "1.0.0"
|
||||
purity: impure
|
||||
signature: "def add_event_dav(summary: str, start: str, end: str = '', *, location: str = '', description: str = '', all_day: bool = False, rrule: str = '', alarm_minutes: int = 0, uid: str = '', base_url: str = DEFAULT_BASE_URL, username: str = DEFAULT_USERNAME, collection_path: str = DEFAULT_COLLECTION, secret_path: str = 'dav/xandikos-enmanuel', timeout_s: float = 20.0, verify_tls: bool = True) -> dict"
|
||||
description: "One-shot que anade UN evento al calendario CalDAV de Enmanuel (Xandikos self-hosted) en una sola llamada. Compone build_vevent (componer el VCALENDAR), extract_or_make_uid (UID si falta), pass_get_secret (resolver la contrasena DAV desde pass) y caldav_put_event (HTTP PUT). Impuro: escritura remota real. Idempotente por UID. La contrasena nunca se logea ni aparece en el resultado. Defaults apuntan al calendario de Enmanuel."
|
||||
tags: [dav, caldav, calendar, event, pipelines]
|
||||
params:
|
||||
- name: summary
|
||||
desc: "titulo del evento (-> SUMMARY). Obligatorio."
|
||||
- name: start
|
||||
desc: "fecha/hora de inicio, p.ej. '2026-06-20T17:00' (naive local), con sufijo 'Z' para UTC, o '2026-06-20' para all_day. Obligatorio."
|
||||
- name: end
|
||||
desc: "fecha/hora de fin. Si vacio y no es all_day, se deriva +1h del start; si all_day, el dia siguiente."
|
||||
- name: location
|
||||
desc: "lugar del evento (-> LOCATION)."
|
||||
- name: description
|
||||
desc: "descripcion del evento (-> DESCRIPTION)."
|
||||
- name: all_day
|
||||
desc: "bool. Si True, evento de dia completo (DTSTART;VALUE=DATE)."
|
||||
- name: rrule
|
||||
desc: "regla de recurrencia RRULE, p.ej. 'FREQ=WEEKLY;BYDAY=MO'."
|
||||
- name: alarm_minutes
|
||||
desc: "int. Si > 0, anade un recordatorio (VALARM display) N minutos antes."
|
||||
- name: uid
|
||||
desc: "UID explicito del evento. Si vacio, se sintetiza determinista del VCALENDAR (re-subir el mismo evento sobrescribe = idempotente)."
|
||||
- name: base_url
|
||||
desc: "URL base del servidor DAV. Default = Xandikos de Enmanuel."
|
||||
- name: username
|
||||
desc: "usuario para HTTP Basic auth. Default 'enmanuel'."
|
||||
- name: collection_path
|
||||
desc: "ruta de la coleccion CalDAV destino. Default '/enmanuel/calendars/calendar/'."
|
||||
- name: secret_path
|
||||
desc: "ruta del secreto en pass con la contrasena DAV. Default 'dav/xandikos-enmanuel'."
|
||||
- name: timeout_s
|
||||
desc: "timeout del PUT en segundos. Default 20.0."
|
||||
- name: verify_tls
|
||||
desc: "si True (default) verifica el certificado TLS. No desactivar salvo entornos de prueba."
|
||||
output: "dict. En exito: {status: 'ok', http_status: int, uid: str, url: str}. En error (sin lanzar): {status: 'error', error: str, uid: str|None, http_status: int|None}. La contrasena nunca aparece en el resultado."
|
||||
uses_functions: [build_vevent_py_core, extract_or_make_uid_py_infra, pass_get_secret_py_infra, caldav_put_event_py_infra]
|
||||
uses_types: []
|
||||
returns: []
|
||||
returns_optional: false
|
||||
error_type: "error_go_core"
|
||||
imports: [os, sys, argparse, json]
|
||||
tested: false
|
||||
tests: []
|
||||
test_file_path: ""
|
||||
file_path: "python/functions/pipelines/add_event_dav.py"
|
||||
---
|
||||
|
||||
## Ejemplo
|
||||
|
||||
```bash
|
||||
# Anadir un evento con hora, lugar y recordatorio (UID sintetico determinista):
|
||||
./fn run add_event_dav --summary "Cita dentista" --start 2026-06-20T17:00 \
|
||||
--end 2026-06-20T18:00 --location "Clinica" --alarm-minutes 30
|
||||
# {"status": "ok", "http_status": 201, "uid": "evt-<md5>", "url": "https://dav-.../enmanuel/calendars/calendar/evt-<md5>.ics"}
|
||||
|
||||
# Evento de dia completo recurrente:
|
||||
./fn run add_event_dav --summary "Cumpleanos" --start 2026-06-20 --all-day \
|
||||
--rrule "FREQ=YEARLY"
|
||||
```
|
||||
|
||||
```python
|
||||
import sys, os
|
||||
sys.path.insert(0, os.path.join("python", "functions"))
|
||||
from pipelines.add_event_dav import add_event_dav
|
||||
|
||||
res = add_event_dav(
|
||||
"Reunion equipo", "2026-06-22T09:00", "2026-06-22T10:00",
|
||||
location="Sala A", description="Sprint review", alarm_minutes=15,
|
||||
)
|
||||
print(res["status"], res["uid"]) # 'ok' evt-...
|
||||
```
|
||||
|
||||
## Cuando usarla
|
||||
|
||||
Cuando quieras anadir un evento al calendario de Enmanuel sin orquestar a mano
|
||||
los pasos (componer el iCal, resolver el secreto, hacer el PUT). Es la operacion
|
||||
one-shot del grupo `dav` para CalDAV. Para subir un `.ics` entero con N eventos
|
||||
usa `import_ics_to_caldav_py_pipelines`; para un solo evento parametrizado, esta.
|
||||
Pasa `uid` explicito si quieres controlar/actualizar un evento concreto; dejalo
|
||||
vacio para crear uno nuevo con UID derivado del contenido.
|
||||
|
||||
## Gotchas
|
||||
|
||||
- **Accion con efecto real (impura)**: hace un HTTP PUT que escribe en el
|
||||
calendario remoto de Enmanuel. No es un dry-run. Verifica `start`/`end` antes
|
||||
de lanzar; un PUT con datos erroneos crea el evento igualmente.
|
||||
- **Idempotente por UID**: el nombre del recurso es `<uid>.ics`. Re-subir el
|
||||
mismo UID SOBRESCRIBE el evento existente (no duplica). Con `uid` vacio el UID
|
||||
es determinista (md5 de summary+start): re-lanzar el mismo evento exacto pisa
|
||||
el anterior; cambiar summary o start crea un recurso nuevo.
|
||||
- **Secreto desde `pass`, nunca hardcode**: la contrasena se resuelve con
|
||||
`pass_get_secret('dav/xandikos-enmanuel')` y NUNCA se logea ni se incluye en el
|
||||
dict de retorno. Si `pass` no esta instalado o la entry no existe, devuelve
|
||||
`{status:'error', error:'pass: ...'}` sin lanzar y sin hacer el PUT.
|
||||
- **`verify_tls=True` por defecto**: no uses `--no-verify-tls` salvo en pruebas
|
||||
controladas. El servidor de Enmanuel tiene certificado valido.
|
||||
- **ValueError de build_vevent**: si falta `summary` o `start`, el pipeline lo
|
||||
captura y devuelve `{status:'error'}` (no propaga la excepcion).
|
||||
Reference in New Issue
Block a user