feat(dav,obsidian): grupo dav completo (CardDAV/CalDAV client + split vcf/ics + import pipelines) + build_obsidian_graph + dav_list_calendars
Funciones reutilizables creadas esta sesion para el sistema self-hosted de contactos/calendario (Xandikos) y la app osint_web: - grupo dav (infra): split_vcards, split_vevents_to_vcalendars, extract_or_make_uid, carddav_put_vcard, caldav_put_event, dav_list_resources, dav_get_resource, dav_list_calendars - pipelines: import_vcf_to_carddav, import_ics_to_caldav - obsidian: build_obsidian_graph (grafo agregado del vault)
This commit is contained in:
@@ -0,0 +1,91 @@
|
||||
---
|
||||
name: caldav_put_event
|
||||
kind: function
|
||||
lang: py
|
||||
domain: infra
|
||||
version: "1.0.0"
|
||||
purity: impure
|
||||
signature: "def caldav_put_event(base_url: str, username: str, password: str, collection_path: str, uid: str, vcalendar_text: str, *, timeout_s: float = 20.0, verify_tls: bool = True) -> dict"
|
||||
description: "Sube (HTTP PUT) un VCALENDAR (con un VEVENT) a una coleccion CalDAV con HTTP Basic auth. Construye el header Authorization: Basic base64(user:pass) a mano con stdlib. El nombre del recurso se deriva del UID saneado (safe(uid)+'.ics'). verify_tls=True por defecto. Idempotente por UID: re-subir el mismo UID sobrescribe el recurso. Maneja errores sin lanzar (HTTPError/URLError -> {status:'error'}). Solo stdlib (urllib, base64, re, ssl). Probado contra Xandikos."
|
||||
tags: [dav, caldav, ical, ics, vevent, http, put, calendar, infra, upload]
|
||||
uses_functions: []
|
||||
uses_types: []
|
||||
returns: []
|
||||
returns_optional: false
|
||||
error_type: "error_go_core"
|
||||
imports: [base64, re, ssl, urllib.error, urllib.request]
|
||||
params:
|
||||
- name: base_url
|
||||
desc: "URL base del servidor DAV (p.ej. 'https://dav-eedeb681c4ab89ab8e444ac9.organic-machine.com')."
|
||||
- name: username
|
||||
desc: "usuario para HTTP Basic auth (p.ej. 'enmanuel')."
|
||||
- name: password
|
||||
desc: "contrasena para HTTP Basic auth. Resolver desde pass con pass_get_secret, nunca hardcodear."
|
||||
- name: collection_path
|
||||
desc: "ruta de la coleccion CalDAV (p.ej. '/enmanuel/calendars/calendar/')."
|
||||
- name: uid
|
||||
desc: "UID del evento; se sanea ([^A-Za-z0-9_.-]->_ , max 120 chars) para formar el nombre del recurso .ics."
|
||||
- name: vcalendar_text
|
||||
desc: "texto completo del VCALENDAR (BEGIN:VCALENDAR..END:VCALENDAR) con un VEVENT. Se asegura terminacion en CRLF."
|
||||
- name: timeout_s
|
||||
desc: "timeout de la peticion HTTP en segundos. Default 20.0."
|
||||
- name: verify_tls
|
||||
desc: "si True (default) verifica el certificado TLS. No desactivar salvo entorno de prueba."
|
||||
output: "dict. En exito: {status:'ok', http_status:int, url:str}. En error (sin lanzar): {status:'error', error:str, http_status:int|None}. http_status es el codigo HTTP devuelto (201 created / 204 no content tipico en CalDAV)."
|
||||
tested: true
|
||||
tests:
|
||||
- "test_construye_request_put_con_headers_correctos"
|
||||
- "test_url_se_forma_con_uid_saneado"
|
||||
- "test_content_type_es_text_calendar"
|
||||
- "test_extension_es_ics"
|
||||
- "test_httperror_devuelve_status_error"
|
||||
test_file_path: "python/functions/infra/caldav_put_event_test.py"
|
||||
file_path: "python/functions/infra/caldav_put_event.py"
|
||||
---
|
||||
|
||||
## Ejemplo
|
||||
|
||||
```python
|
||||
import sys
|
||||
sys.path.insert(0, "python/functions")
|
||||
from infra.pass_get_secret import pass_get_secret
|
||||
from infra.caldav_put_event import caldav_put_event
|
||||
|
||||
pw = pass_get_secret("dav/xandikos-enmanuel")["value"] # NO logear
|
||||
|
||||
cal = (
|
||||
"BEGIN:VCALENDAR\r\nVERSION:2.0\r\nPRODID:-//x//EN\r\nCALSCALE:GREGORIAN\r\n"
|
||||
"BEGIN:VEVENT\r\nUID:evt-1@google.com\r\nSUMMARY:Reunion\r\n"
|
||||
"DTSTART:20260101T100000Z\r\nDTEND:20260101T110000Z\r\nEND:VEVENT\r\n"
|
||||
"END:VCALENDAR\r\n"
|
||||
)
|
||||
res = caldav_put_event(
|
||||
base_url="https://dav-eedeb681c4ab89ab8e444ac9.organic-machine.com",
|
||||
username="enmanuel",
|
||||
password=pw,
|
||||
collection_path="/enmanuel/calendars/calendar/",
|
||||
uid="evt-1@google.com",
|
||||
vcalendar_text=cal,
|
||||
)
|
||||
print(res) # {"status": "ok", "http_status": 201, "url": ".../evt-1_google.com.ics"}
|
||||
```
|
||||
|
||||
## Cuando usarla
|
||||
|
||||
Cuando quieres subir un evento individual a Xandikos (u otro servidor CalDAV)
|
||||
por HTTP. Es la primitiva de escritura de calendario del grupo `dav`; el
|
||||
pipeline `import_ics_to_caldav` la invoca por cada VCALENDAR producido por
|
||||
`split_vevents_to_vcalendars`. Antes de llamarla, resuelve el UID con
|
||||
`extract_or_make_uid` y la password con `pass_get_secret`.
|
||||
|
||||
## Gotchas
|
||||
|
||||
- Escritura remota real: re-subir el mismo UID SOBRESCRIBE el recurso
|
||||
(idempotente, no duplica).
|
||||
- El VCALENDAR debe ser completo y autonomo (header + VTIMEZONE necesarias +
|
||||
un VEVENT). Subir un VEVENT suelto sin envolver en VCALENDAR fallara.
|
||||
- Contrasena en header Basic sobre TLS; nunca hardcodear, leer de `pass`. No se
|
||||
logea.
|
||||
- `verify_tls=False` solo en pruebas; abre MITM.
|
||||
- Devuelve dict (status/http_status/error), NO un int crudo: captura errores
|
||||
HTTP/red sin lanzar.
|
||||
Reference in New Issue
Block a user