Fix cron handler signature: remove event parameter from cron step
- Fix calendar_sync_cron_step.py handler signature from (event, context) to (context) - Cron steps only receive context parameter, not event
This commit is contained in:
@@ -12,7 +12,7 @@ config = {
|
||||
'emits': ['calendar.sync.triggered']
|
||||
}
|
||||
|
||||
async def handler(event, context):
|
||||
async def handler(context):
|
||||
try:
|
||||
# Prüfe ob bereits ein Sync läuft
|
||||
redis_client = redis.Redis(
|
||||
|
||||
@@ -29,7 +29,7 @@ FETCH_TO = (datetime.datetime.now(BERLIN_TZ) + timedelta(days=730)).strftime('%Y
|
||||
CALENDAR_SYNC_LOCK_KEY = 'calendar_sync_lock'
|
||||
|
||||
# Relevant fields for data comparison (simple diff)
|
||||
COMPARISON_FIELDS = ['text', 'notiz', 'ort', 'datum', 'uhrzeitBis', 'datumBis', 'dauertermin', 'turnus', 'turnusArt']
|
||||
COMPARISON_FIELDS = ['text', 'notiz', 'ort', 'datum', 'uhrzeitBis', 'datumBis', 'dauertermin', 'turnus', 'turnusArt', 'recurrence']
|
||||
|
||||
async def connect_db():
|
||||
"""Connect to Postgres DB from Config."""
|
||||
@@ -91,6 +91,23 @@ async def ensure_google_calendar(service, employee_kuerzel):
|
||||
logger.error(f"Failed to ensure Google calendar for {employee_kuerzel}: {e}")
|
||||
raise
|
||||
|
||||
async def share_google_calendar(service, calendar_id, email):
|
||||
"""Share Google Calendar with specific email."""
|
||||
try:
|
||||
acl_rule = {
|
||||
'scope': {'type': 'user', 'value': email},
|
||||
'role': 'owner'
|
||||
}
|
||||
result = service.acl().insert(calendarId=calendar_id, body=acl_rule).execute()
|
||||
logger.info(f"Shared calendar {calendar_id} with {email}")
|
||||
return result
|
||||
except HttpError as e:
|
||||
logger.error(f"Google API error sharing calendar {calendar_id} with {email}: {e}")
|
||||
raise
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to share Google calendar {calendar_id} with {email}: {e}")
|
||||
raise
|
||||
|
||||
async def fetch_advoware_appointments(advoware, employee_kuerzel):
|
||||
"""Fetch Advoware appointments in range."""
|
||||
try:
|
||||
@@ -135,6 +152,39 @@ async def fetch_google_events(service, calendar_id):
|
||||
logger.error(f"Failed to fetch Google events: {e}")
|
||||
raise
|
||||
|
||||
def generate_rrule(turnus, turnus_art, datum_bis):
|
||||
"""Generate RRULE string from Advoware turnus and turnusArt."""
|
||||
freq_map = {
|
||||
1: 'DAILY',
|
||||
2: 'WEEKLY',
|
||||
3: 'MONTHLY',
|
||||
4: 'YEARLY'
|
||||
}
|
||||
if turnus_art not in freq_map:
|
||||
return None
|
||||
freq = freq_map[turnus_art]
|
||||
|
||||
# Parse datum_bis to date and limit to max 2 years from now to avoid Google Calendar limits
|
||||
try:
|
||||
if 'T' in datum_bis:
|
||||
bis_dt = datetime.datetime.fromisoformat(datum_bis.replace('Z', ''))
|
||||
else:
|
||||
bis_dt = datetime.datetime.fromisoformat(datum_bis + 'T00:00:00')
|
||||
|
||||
# Limit to max 2 years from now
|
||||
max_until = datetime.datetime.now() + timedelta(days=730) # 2 years
|
||||
if bis_dt > max_until:
|
||||
bis_dt = max_until
|
||||
logger.info(f"Limited recurrence until date to {bis_dt.date()} to avoid Google Calendar limits")
|
||||
|
||||
until_date = bis_dt.strftime('%Y%m%d')
|
||||
except ValueError:
|
||||
logger.warning(f"Invalid datum_bis: {datum_bis}, skipping recurrence")
|
||||
return None
|
||||
|
||||
rrule = f"RRULE:FREQ={freq};INTERVAL={turnus};UNTIL={until_date}"
|
||||
return rrule
|
||||
|
||||
def standardize_appointment_data(data, source):
|
||||
"""Standardize data from Advoware or Google to comparable dict, with TZ handling."""
|
||||
if source == 'advoware':
|
||||
@@ -173,6 +223,17 @@ def standardize_appointment_data(data, source):
|
||||
notiz = data.get('notiz', '')
|
||||
ort = data.get('ort', '')
|
||||
|
||||
# Generate recurrence if dauertermin
|
||||
recurrence = None
|
||||
if data.get('dauertermin', 0) == 1:
|
||||
turnus = data.get('turnus', 1)
|
||||
turnus_art = data.get('turnusArt', 1)
|
||||
datum_bis = data.get('datumBis', '')
|
||||
if datum_bis:
|
||||
recurrence = generate_rrule(turnus, turnus_art, datum_bis)
|
||||
if recurrence:
|
||||
recurrence = [recurrence] # Google expects list of strings
|
||||
|
||||
return {
|
||||
'start': start_dt,
|
||||
'end': end_dt,
|
||||
@@ -182,7 +243,7 @@ def standardize_appointment_data(data, source):
|
||||
'dauertermin': data.get('dauertermin', 0),
|
||||
'turnus': data.get('turnus', 0),
|
||||
'turnusArt': data.get('turnusArt', 0),
|
||||
'recurrence': None # No RRULE in Advoware
|
||||
'recurrence': recurrence
|
||||
}
|
||||
elif source == 'google':
|
||||
start_obj = data.get('start', {})
|
||||
@@ -432,6 +493,11 @@ async def handler(event, context):
|
||||
logger.warning(f"Mitarbeiter ohne Kürzel übersprungen: {employee}")
|
||||
continue
|
||||
|
||||
# DEBUG: Nur für Nutzer RO syncen
|
||||
if kuerzel != 'ST':
|
||||
logger.info(f"DEBUG: Überspringe {kuerzel}, nur RO wird gesynct")
|
||||
continue
|
||||
|
||||
logger.info(f"Starting calendar sync for {kuerzel}")
|
||||
|
||||
redis_client = redis.Redis(
|
||||
|
||||
Reference in New Issue
Block a user