From 9de30d0cbf8bc9a3aadd81f703d7cc7f055f952f Mon Sep 17 00:00:00 2001 From: Valentin Ochs Date: Fri, 17 Jul 2020 21:38:56 +0200 Subject: [PATCH] Initial commit --- .gitignore | 2 + auth.yaml.example | 10 ++++ sync.py | 119 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 131 insertions(+) create mode 100644 .gitignore create mode 100644 auth.yaml.example create mode 100644 sync.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..594229f --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +auth.yaml +data.yaml diff --git a/auth.yaml.example b/auth.yaml.example new file mode 100644 index 0000000..a5e4dea --- /dev/null +++ b/auth.yaml.example @@ -0,0 +1,10 @@ +logins: + test_login: + password: hoarse_battery_steeple + url: https://example.com/remote.php/dav + user: root +cals: +- login: test_login + url: https://example.com/remote.php/dav/calendars/root/cal_1 +- login: test_login + url: https://example.com/remote.php/dav/calendars/root/cal_2 diff --git a/sync.py b/sync.py new file mode 100644 index 0000000..9c00818 --- /dev/null +++ b/sync.py @@ -0,0 +1,119 @@ +import yaml +import caldav +import sys + +with open('auth.yaml') as f: + auth = yaml.full_load(f) +try: + with open('data.yaml') as f: + known = yaml.full_load(f) +except: + known = {} + +logins = {} +for login, content in auth['logins'].items(): + logins[login] = caldav.DAVClient(url=content['url'], username=content['user'], password=content['password']) + +cals = [] +for cal in auth['cals']: + cals.append(caldav.Calendar(client = logins[cal['login']], url = cal['url'])) + +new = {} +changed = {} +deleted = {} + +def cal_contains_uid(cal, uid): + try: + event = cal.event_by_uid(uid) + return True + except caldav.lib.error.NotFoundError: + return False + +for cal in cals: + for event in cal.events(): + uid = event.vobject_instance.vevent.uid.value + data = event.data + entry = (cal.canonical_url, data) + + if uid not in known: + if uid not in new: + new[uid] = [entry] + else: + new[uid].append(entry) + else: + if data != known[uid]: + if uid not in changed: + changed[uid] = [entry] + else: + changed[uid].append(entry) +for uid, data in known.items(): + for cal in cals: + if not cal_contains_uid(cal, uid): + if uid not in deleted: + deleted[uid] = [cal.canonical_url] + else: + deleted[uid].append(cal.canonical_url) + +print("New:") +print(new) +print() +print("Changed:") +print(changed) +print() +print("Deleted:") +print(deleted) +print() + +for uid, arr in new.items(): + if len(set([entry[1] for entry in arr])) != 1: + print("Multiple new entries with the same UID (%s) detected:" % (uid,), file=sys.stderr) + for ev in arr: + print(" %s: %s" % (ev[0], ev[1].vobject_instance.vevent.summary.value), file = sys.stderr) + print("", file=sys.stderr) + continue + + entry = arr[0] + known_cals = [ entry[0] for entry in arr ] + for cal in cals: + if cal.canonical_url not in known_cals: + cal.save_event(entry[1], no_overwrite=True) + known[uid] = entry[1] + +for uid, arr in changed.items(): + if uid in deleted: + print("Changed entry with UID (%s) and was also deleted:" % (uid, ), file=sys.stderr) + print("Deletions in:", file=sys.stderr) + for cal in deleted[uid]: + print(" - %s" % (cal,), file=sys.stderr) + print("Changes in:", file=sys.stderr) + for entry in arr: + print(" - %s" % (entry[0],), file=sys.stderr) + print("", file=sys.stderr) + continue + + if len(set([entry[1] for entry in arr])) != 1: + print("Multiple changed entries with the same UID (%s) detected:" % (uid,), file=sys.stderr) + for ev in arr: + print(" %s: %s" % (ev[0], ev[1].vobject_instance.vevent.summary.value), file = sys.stderr) + del deleted[uid] + continue + + entry = arr[0] + changed_cals = [ entry[0] for entry in arr ] + for cal in cals: + if cal.canonical_url not in changed_cals: + cal.save_event(entry[1], no_create=True) + known[uid] = entry[1] + +for uid in deleted: + for cal in cals: + try: + cal.event_by_uid(uid).delete() + except: + pass + +print(known) + +with open("data.yaml", "w") as f: + yaml.dump(known, f) +