diff --git a/src/carddav_client.py b/src/carddav_client.py index 81fcc0d..ae3bb73 100644 --- a/src/carddav_client.py +++ b/src/carddav_client.py @@ -15,8 +15,9 @@ antwortet der Server mit 403 valid-sync-token, dann fällt der Client automatisc auf einen vollständigen Re-Sync zurück. """ import logging +import os +from urllib.parse import urljoin, urlparse from xml.etree import ElementTree as ET -from urllib.parse import urljoin import requests @@ -35,10 +36,11 @@ class SyncTokenInvalid(Exception): class CardDAVClient: - def __init__(self, base_url: str, username: str, password: str, timeout: int = 30): + def __init__(self, base_url: str, username: str, password: str, timeout: int = 30, account_name: str = ""): self.base_url = base_url self.auth = (username, password) self.timeout = timeout + self.account_name = account_name self.session = requests.Session() def _request(self, method: str, url: str, body: str, depth: str = "0"): @@ -49,6 +51,7 @@ class CardDAVClient: if resp.status_code == 403 and "valid-sync-token" in resp.text: raise SyncTokenInvalid("sync-token vom Server abgelehnt") resp.raise_for_status() + self._dump_debug(method, url, resp) return ET.fromstring(resp.content) def discover_principal(self) -> str: @@ -148,3 +151,16 @@ class CardDAVClient: if href.startswith("http"): return href return urljoin(self.base_url, href) + + def _dump_debug(self, method: str, url: str, resp: requests.Response): + dump_dir = f"/app/debug/carddav/{self.account_name}" if self.account_name else "/app/debug/carddav" + try: + os.makedirs(dump_dir, exist_ok=True) + path = urlparse(url).path.rstrip("/").replace("/", "_") or "root" + filename = f"{method}_{path}.xml" + filepath = os.path.join(dump_dir, filename) + with open(filepath, "w", encoding="utf-8") as f: + f.write(resp.text) + logger.debug("CardDAV-Debug-Dump: %s", filepath) + except Exception: + logger.warning("Debug-Dump fehlgeschlagen", exc_info=True) diff --git a/src/config.py b/src/config.py index 4bef023..fab57cf 100644 --- a/src/config.py +++ b/src/config.py @@ -1,7 +1,8 @@ # Copyright (c) 2026 Stefan Koelle (https://stefankoelle.de) # Licensed under the MIT License. See LICENSE file in project root for details. -import os import json +import os + from dotenv import load_dotenv load_dotenv() diff --git a/src/sync.py b/src/sync.py index 675f6d4..678028d 100644 --- a/src/sync.py +++ b/src/sync.py @@ -19,7 +19,7 @@ logger = logging.getLogger("sync") def sync_account(conn, account, href_to_uid_cache: dict): - client = CardDAVClient(ICLOUD_BASE_URL, account.apple_email, account.apple_app_password) + client = CardDAVClient(ICLOUD_BASE_URL, account.apple_email, account.apple_app_password, account_name=account.name) collection_url = client.discover_collection() stored_token = db.get_sync_token(conn, account.name)