library/calendar_sync.py aktualisiert

This commit is contained in:
2025-07-12 08:52:17 +00:00
parent b854ae80d7
commit 8118c0645e

View File

@ -5,16 +5,33 @@ from caldav import DAVClient
import vobject import vobject
import requests import requests
from urllib.parse import urlparse from urllib.parse import urlparse
import logging
# Logging für Debugging einrichten
logging.basicConfig(level=logging.WARNING)
def fetch_ics_events(url, user=None, password=None): def fetch_ics_events(url, user=None, password=None):
try: try:
response = requests.get(url, auth=(user, password) if user else None) response = requests.get(url, auth=(user, password) if user else None)
response.raise_for_status() response.raise_for_status()
events = [] events = []
for calendar in vobject.readComponents(response.text): ics_data = response.text
for component in calendar.components():
if component.name == 'VEVENT': # Debug-Ausgabe für ungültige Daten
events.append(component) if not ics_data.strip():
logging.warning("Leere ICS-Daten empfangen")
return events
try:
for calendar in vobject.readComponents(ics_data):
for component in calendar.components():
if component.name == 'VEVENT':
if hasattr(component, 'uid') and component.uid.value:
events.append(component)
else:
logging.warning("VEVENT ohne UID übersprungen")
except vobject.base.ParseError as e:
logging.error(f"Parse-Fehler in ICS-Daten: {str(e)}")
return events return events
except Exception as e: except Exception as e:
raise Exception(f"ICS-Fehler: {str(e)}") raise Exception(f"ICS-Fehler: {str(e)}")
@ -37,6 +54,27 @@ def connect_caldav(url, user=None, password=None, verify_ssl=True):
except Exception as e: except Exception as e:
raise Exception(f"CalDAV-Fehler: {str(e)}") raise Exception(f"CalDAV-Fehler: {str(e)}")
def safe_caldav_event_processing(event):
try:
if event is None or not hasattr(event, 'data') or not event.data:
return None
for calendar in vobject.readComponents(event.data):
for component in calendar.components():
if component.name == 'VEVENT' and hasattr(component, 'uid'):
return {
'uid': str(component.uid),
'event_object': event,
'data': event.data
}
return None
except vobject.base.ParseError:
logging.warning("Parse-Fehler in CalDAV-Event, überspringe")
return None
except Exception as e:
logging.error(f"Fehler bei Event-Verarbeitung: {str(e)}")
return None
def sync_ics_to_caldav(module): def sync_ics_to_caldav(module):
ics_events = fetch_ics_events( ics_events = fetch_ics_events(
module.params['source_url'], module.params['source_url'],
@ -53,43 +91,54 @@ def sync_ics_to_caldav(module):
existing_events = {} existing_events = {}
for event in target_cal.events(): for event in target_cal.events():
if event is None: processed = safe_caldav_event_processing(event)
continue if processed:
data = getattr(event, 'data', None) existing_events[processed['uid']] = processed
if not data:
continue
try:
for calendar in vobject.readComponents(data):
for component in calendar.components():
if component.name == 'VEVENT' and hasattr(component, 'uid'):
uid = str(component.uid)
existing_events[uid] = event
except Exception:
continue
changed = False changed = False
results = {'added': [], 'updated': [], 'removed': []} results = {'added': [], 'updated': [], 'removed': []}
for vevent in ics_events: for vevent in ics_events:
uid = str(vevent.uid) uid = str(vevent.uid)
ical_data = vevent.serialize() try:
ical_data = vevent.serialize()
except Exception as e:
logging.error(f"Serialisierungsfehler für UID {uid}: {str(e)}")
continue
if not ical_data.strip():
logging.warning(f"Leere iCal-Daten für UID {uid}, überspringe")
continue
if uid not in existing_events: if uid not in existing_events:
target_cal.add_event(ical_data) try:
results['added'].append(uid) target_cal.add_event(ical_data)
changed = True results['added'].append(uid)
elif ical_data != existing_events[uid].data: changed = True
existing_events[uid].data = ical_data except Exception as e:
existing_events[uid].save() logging.error(f"Hinzufügen fehlgeschlagen für UID {uid}: {str(e)}")
results['updated'].append(uid) else:
changed = True existing_data = existing_events[uid]['data']
if ical_data != existing_data:
try:
event_obj = existing_events[uid]['event_object']
event_obj.data = ical_data
event_obj.save()
results['updated'].append(uid)
changed = True
except Exception as e:
logging.error(f"Aktualisieren fehlgeschlagen für UID {uid}: {str(e)}")
if module.params['purge']: if module.params['purge']:
current_uids = {str(e.uid) for e in ics_events} current_uids = {str(e.uid) for e in ics_events}
for uid in set(existing_events.keys()) - current_uids: for uid, event_info in existing_events.items():
existing_events[uid].delete() if uid not in current_uids:
results['removed'].append(uid) try:
changed = True event_info['event_object'].delete()
results['removed'].append(uid)
changed = True
except Exception as e:
logging.error(f"Löschen fehlgeschlagen für UID {uid}: {str(e)}")
return changed, results return changed, results
@ -114,4 +163,4 @@ def run_module():
module.fail_json(msg=str(e)) module.fail_json(msg=str(e))
if __name__ == '__main__': if __name__ == '__main__':
run_module() run_module()