# lead-engine/trading_twins/debug_calendar.py import os import requests import json from datetime import datetime, timedelta from zoneinfo import ZoneInfo from threading import Thread, Lock import uvicorn from fastapi import FastAPI, Response, BackgroundTasks import msal from dotenv import load_dotenv # Load environment variables from /app/.env load_dotenv(dotenv_path="/app/.env", override=True) # --- Zeitzonen-Konfiguration --- TZ_BERLIN = ZoneInfo("Europe/Berlin") # --- Konfiguration --- # Credentials für die Kalender-Lese-App (e.melcer) CAL_APPID = os.getenv("CAL_APPID") CAL_SECRET = os.getenv("CAL_SECRET") CAL_TENNANT_ID = os.getenv("CAL_TENNANT_ID") TARGET_EMAIL = "e.melcer@robo-planet.de" GRAPH_API_ENDPOINT = "https://graph.microsoft.com/v1.0" def get_access_token(client_id, client_secret, tenant_id): if not all([client_id, client_secret, tenant_id]): print("❌ Credentials missing in .env for Calendar Access") return None authority = f"https://login.microsoftonline.com/{tenant_id}" app = msal.ConfidentialClientApplication(client_id=client_id, authority=authority, client_credential=client_secret) # Scopes for Calendar.Read scopes = ["https://graph.microsoft.com/.default"] result = app.acquire_token_silent(scopes, account=None) if not result: result = app.acquire_token_for_client(scopes=scopes) if "access_token" in result: print("✅ Successfully acquired Access Token for Calendar.") return result["access_token"] else: print(f"❌ Failed to acquire Access Token: {result.get('error_description')}") return None def check_calendar_availability(): print(f"--- Checking Calendar for {TARGET_EMAIL} ---") token = get_access_token(CAL_APPID, CAL_SECRET, CAL_TENNANT_ID) if not token: print("❌ Cannot proceed without Access Token.") return None headers = {"Authorization": f"Bearer {token}", "Content-Type": "application/json", "Prefer": 'outlook.timezone="Europe/Berlin"'} # Get next 5 events starting from now start_time = datetime.now(TZ_BERLIN).replace(minute=0, second=0, microsecond=0) if start_time.hour >= 17: start_time += timedelta(days=1); start_time = start_time.replace(hour=8) end_time = start_time + timedelta(days=3) payload = { "schedules": [TARGET_EMAIL], "startTime": {"dateTime": start_time.isoformat(), "timeZone": "Europe/Berlin"}, "endTime": {"dateTime": end_time.isoformat(), "timeZone": "Europe/Berlin"}, "availabilityViewInterval": 60 # Check availability in 1-hour blocks } url = f"{GRAPH_API_ENDPOINT}/users/{TARGET_EMAIL}/calendarView" params = { "startDateTime": start_time.isoformat(), "endDateTime": end_time.isoformat(), "$top": 5 } try: response = requests.get(url, headers=headers, params=params) if response.status_code == 200: events = response.json().get("value", []) if not events: print("✅ API call successful, but no upcoming events found.") return [] print("\n--- Next 5 Upcoming Events ---") for event in events: subject = event.get('subject', 'No Subject') start = event.get('start', {}).get('dateTime') if start: # Fix for 7-digit microseconds from Graph API (e.g. 2026-03-09T17:00:00.0000000) if "." in start: main_part, frac_part = start.split(".") # Truncate to 6 digits max or remove if empty start = f"{main_part}.{frac_part[:6]}" dt_obj = datetime.fromisoformat(start.replace('Z', '+00:00')).astimezone(TZ_BERLIN) start_formatted = dt_obj.strftime('%A, %d.%m.%Y um %H:%M Uhr') else: start_formatted = "N/A" print(f"🗓️ {subject} -> {start_formatted}") return events else: print(f"❌ HTTP Error: {response.status_code} - {response.text}") return None except Exception as e: print(f"❌ An unexpected error occurred: {e}") return None if __name__ == "__main__": check_calendar_availability()