mirror of
https://github.com/skoelle/icloud-contacts-sync.git
synced 2026-09-17 23:40:24 +00:00
fix 3
This commit is contained in:
@@ -95,6 +95,7 @@ def upsert_contacts(conn, contacts: list[dict], run_id: str):
|
|||||||
with conn.cursor() as cur:
|
with conn.cursor() as cur:
|
||||||
for c in contacts:
|
for c in contacts:
|
||||||
c["sync_run_id"] = run_id
|
c["sync_run_id"] = run_id
|
||||||
|
c = _sanitize_contact(c)
|
||||||
cols = list(c.keys())
|
cols = list(c.keys())
|
||||||
placeholders = ", ".join(["%s"] * len(cols))
|
placeholders = ", ".join(["%s"] * len(cols))
|
||||||
update_clause = ", ".join(f"{col}=VALUES({col})" for col in cols if col not in ("account", "uid"))
|
update_clause = ", ".join(f"{col}=VALUES({col})" for col in cols if col not in ("account", "uid"))
|
||||||
@@ -118,12 +119,30 @@ def delete_contacts_by_href_uids(conn, account: str, uids: list[str]):
|
|||||||
conn.commit()
|
conn.commit()
|
||||||
|
|
||||||
|
|
||||||
|
def _sanitize_contact(c: dict) -> dict:
|
||||||
|
"""Stellt sicher, dass alle Werte Skalare sind (kein tuple/list/dict)."""
|
||||||
|
sanitized = {}
|
||||||
|
for k, v in c.items():
|
||||||
|
if isinstance(v, (list, tuple)):
|
||||||
|
# JSON-Felder sind bereits serialisiert, andere zu Strings machen
|
||||||
|
if k in ("emails", "phones", "addresses", "urls", "social_profiles", "related_names", "categories"):
|
||||||
|
sanitized[k] = v # bereits JSON-String
|
||||||
|
else:
|
||||||
|
sanitized[k] = ",".join(str(x) for x in v) if v else None
|
||||||
|
elif isinstance(v, dict):
|
||||||
|
sanitized[k] = str(v) if v else None
|
||||||
|
else:
|
||||||
|
sanitized[k] = v
|
||||||
|
return sanitized
|
||||||
|
|
||||||
|
|
||||||
def replace_all_contacts_for_account(conn, account: str, contacts: list[dict], run_id: str):
|
def replace_all_contacts_for_account(conn, account: str, contacts: list[dict], run_id: str):
|
||||||
"""Voller Re-Sync für einen Account (initialer Lauf oder Recovery nach ungültigem sync-token)."""
|
"""Voller Re-Sync für einen Account (initialer Lauf oder Recovery nach ungültigem sync-token)."""
|
||||||
with conn.cursor() as cur:
|
with conn.cursor() as cur:
|
||||||
cur.execute("DELETE FROM contacts WHERE account = %s", (account,))
|
cur.execute("DELETE FROM contacts WHERE account = %s", (account,))
|
||||||
for c in contacts:
|
for c in contacts:
|
||||||
c["sync_run_id"] = run_id
|
c["sync_run_id"] = run_id
|
||||||
|
c = _sanitize_contact(c)
|
||||||
cols = ", ".join(c.keys())
|
cols = ", ".join(c.keys())
|
||||||
placeholders = ", ".join(["%s"] * len(c))
|
placeholders = ", ".join(["%s"] * len(c))
|
||||||
cur.execute(f"INSERT INTO contacts ({cols}) VALUES ({placeholders})", list(c.values()))
|
cur.execute(f"INSERT INTO contacts ({cols}) VALUES ({placeholders})", list(c.values()))
|
||||||
|
|||||||
+5
-5
@@ -44,11 +44,11 @@ def parse_vcard(raw_text: str, account: str) -> dict | None:
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
n = getattr(vcard, "n", None)
|
n = getattr(vcard, "n", None)
|
||||||
given_name = n.value.given if n else None
|
given_name = _scalar(n.value.given) if n else None
|
||||||
family_name = n.value.family if n else None
|
family_name = _scalar(n.value.family) if n else None
|
||||||
middle_name = n.value.additional if n else None
|
middle_name = _scalar(n.value.additional) if n else None
|
||||||
prefix = n.value.prefix if n else None
|
prefix = _scalar(n.value.prefix) if n else None
|
||||||
suffix = n.value.suffix if n else None
|
suffix = _scalar(n.value.suffix) if n else None
|
||||||
|
|
||||||
emails = [{"type": _type_str(e), "value": e.value}
|
emails = [{"type": _type_str(e), "value": e.value}
|
||||||
for e in getattr(vcard, "email_list", [])]
|
for e in getattr(vcard, "email_list", [])]
|
||||||
|
|||||||
Reference in New Issue
Block a user