feat: Implement Google Calendar integration

- Implements `get_available_slots` to find open time slots.
- Implements `create_event` to schedule new events.
- Uses a service account for server-to-server authentication.
- Adds `GOOGLE_SERVICE_ACCOUNT_FILE` and `CALENDAR_ID` to the configuration.
- Updates `tasks.md` to reflect the completion of the integration.
- Includes error handling for Google Calendar API calls.
This commit is contained in:
google-labs-jules[bot]
2025-12-15 21:57:08 +00:00
parent 6bdae0869c
commit 2a8f8dd537
4 changed files with 90 additions and 18 deletions

View File

@@ -1,17 +1,91 @@
# app/calendar.py
def get_available_slots():
"""
Fetches available calendar slots.
"""
print("Fetching available slots from Google Calendar...")
# TODO: Implement Google Calendar API integration
return []
import datetime
from google.oauth2 import service_account
from googleapiclient.discovery import build
from googleapiclient.errors import HttpError
from app.config import GOOGLE_SERVICE_ACCOUNT_FILE, CALENDAR_ID
def create_event(summary, start_time, end_time, attendees):
# Set up the Calendar API
SCOPES = ["https://www.googleapis.com/auth/calendar"]
creds = service_account.Credentials.from_service_account_file(
GOOGLE_SERVICE_ACCOUNT_FILE, scopes=SCOPES
)
service = build("calendar", "v3", credentials=creds)
def get_available_slots(
start_time, end_time, duration_minutes=30, calendar_id=CALENDAR_ID
):
"""
Fetches available calendar slots within a given time range.
"""
try:
time_min = start_time.isoformat()
time_max = end_time.isoformat()
freebusy_query = {
"timeMin": time_min,
"timeMax": time_max,
"timeZone": "UTC",
"items": [{"id": calendar_id}],
}
freebusy_result = service.freebusy().query(body=freebusy_query).execute()
busy_slots = freebusy_result["calendars"][calendar_id]["busy"]
# Create a list of all potential slots
potential_slots = []
current_time = start_time
while current_time + datetime.timedelta(minutes=duration_minutes) <= end_time:
potential_slots.append(
(
current_time,
current_time + datetime.timedelta(minutes=duration_minutes),
)
)
current_time += datetime.timedelta(minutes=duration_minutes)
# Filter out busy slots
available_slots = []
for slot_start, slot_end in potential_slots:
is_busy = False
for busy in busy_slots:
busy_start = datetime.datetime.fromisoformat(busy["start"])
busy_end = datetime.datetime.fromisoformat(busy["end"])
if max(slot_start, busy_start) < min(slot_end, busy_end):
is_busy = True
break
if not is_busy:
available_slots.append((slot_start, slot_end))
return available_slots
except HttpError as error:
print(f"An error occurred: {error}")
return []
def create_event(summary, start_time, end_time, attendees, calendar_id=CALENDAR_ID):
"""
Creates a new event in the calendar.
"""
print(f"Creating event: {summary}")
# TODO: Implement Google Calendar API integration
return None
event = {
"summary": summary,
"start": {
"dateTime": start_time.isoformat(),
"timeZone": "UTC",
},
"end": {
"dateTime": end_time.isoformat(),
"timeZone": "UTC",
},
"attendees": [{"email": email} for email in attendees],
}
try:
created_event = (
service.events().insert(calendarId=calendar_id, body=event).execute()
)
return created_event
except HttpError as error:
print(f"An error occurred: {error}")
return None

View File

@@ -5,9 +5,8 @@ TELEGRAM_BOT_TOKEN = os.getenv("TELEGRAM_BOT_TOKEN")
OWNER_CHAT_ID = os.getenv("OWNER_CHAT_ID")
ADMIN_CHAT_IDS = os.getenv("ADMIN_CHAT_IDS", "").split(",")
TEAM_CHAT_IDS = os.getenv("TEAM_CHAT_IDS", "").split(",")
GOOGLE_CLIENT_ID = os.getenv("GOOGLE_CLIENT_ID")
GOOGLE_CLIENT_SECRET = os.getenv("GOOGLE_CLIENT_SECRET")
GOOGLE_REFRESH_TOKEN = os.getenv("GOOGLE_REFRESH_TOKEN")
GOOGLE_SERVICE_ACCOUNT_FILE = os.getenv("GOOGLE_SERVICE_ACCOUNT_FILE")
CALENDAR_ID = os.getenv("CALENDAR_ID")
N8N_WEBHOOK_URL = os.getenv("N8N_WEBHOOK_URL")
OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")
TIMEZONE = os.getenv("TIMEZONE", "America/Mexico_City")