library/calendar_sync.py aktualisiert
This commit is contained in:
@ -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
|
||||||
|
|
||||||
|
# Debug-Ausgabe für ungültige Daten
|
||||||
|
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():
|
for component in calendar.components():
|
||||||
if component.name == 'VEVENT':
|
if component.name == 'VEVENT':
|
||||||
|
if hasattr(component, 'uid') and component.uid.value:
|
||||||
events.append(component)
|
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)
|
||||||
|
try:
|
||||||
ical_data = vevent.serialize()
|
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:
|
||||||
|
try:
|
||||||
target_cal.add_event(ical_data)
|
target_cal.add_event(ical_data)
|
||||||
results['added'].append(uid)
|
results['added'].append(uid)
|
||||||
changed = True
|
changed = True
|
||||||
elif ical_data != existing_events[uid].data:
|
except Exception as e:
|
||||||
existing_events[uid].data = ical_data
|
logging.error(f"Hinzufügen fehlgeschlagen für UID {uid}: {str(e)}")
|
||||||
existing_events[uid].save()
|
else:
|
||||||
|
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)
|
results['updated'].append(uid)
|
||||||
changed = True
|
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:
|
||||||
|
try:
|
||||||
|
event_info['event_object'].delete()
|
||||||
results['removed'].append(uid)
|
results['removed'].append(uid)
|
||||||
changed = True
|
changed = True
|
||||||
|
except Exception as e:
|
||||||
|
logging.error(f"Löschen fehlgeschlagen für UID {uid}: {str(e)}")
|
||||||
|
|
||||||
return changed, results
|
return changed, results
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user