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:
root
2025-10-23 17:33:58 +00:00
parent 080eebd5ea
commit 08b21ef268
3 changed files with 70 additions and 4 deletions

View File

@@ -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(

View File

@@ -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(