106 lines
4.2 KiB
Python
106 lines
4.2 KiB
Python
# 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() |