Files
space-booking/backend/app/services/google_calendar_service.py
Claude Agent df4031d99c feat: Space Booking System - MVP complet
Sistem web pentru rezervarea de birouri și săli de ședință
cu flux de aprobare administrativă.

Stack: FastAPI + Vue.js 3 + SQLite + TypeScript

Features implementate:
- Autentificare JWT + Self-registration cu email verification
- CRUD Spații, Utilizatori, Settings (Admin)
- Calendar interactiv (FullCalendar) cu drag-and-drop
- Creare rezervări cu validare (durată, program, overlap, max/zi)
- Rezervări recurente (săptămânal)
- Admin: aprobare/respingere/anulare cereri
- Admin: creare directă rezervări (bypass approval)
- Admin: editare orice rezervare
- User: editare/anulare rezervări proprii
- Notificări in-app (bell icon + dropdown)
- Notificări email (async SMTP cu BackgroundTasks)
- Jurnal acțiuni administrative (audit log)
- Rapoarte avansate (utilizare, top users, approval rate)
- Șabloane rezervări (booking templates)
- Atașamente fișiere (upload/download)
- Conflict warnings (verificare disponibilitate real-time)
- Integrare Google Calendar (OAuth2)
- Suport timezone (UTC storage + user preference)
- 225+ teste backend

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-09 17:51:29 +00:00

174 lines
4.8 KiB
Python

"""Google Calendar integration service."""
from datetime import datetime
from typing import Optional
from google.auth.transport.requests import Request
from google.oauth2.credentials import Credentials
from googleapiclient.discovery import build
from sqlalchemy.orm import Session
from app.core.config import settings
from app.models.booking import Booking
from app.models.google_calendar_token import GoogleCalendarToken
def get_google_calendar_service(db: Session, user_id: int):
"""
Get authenticated Google Calendar service for user.
Args:
db: Database session
user_id: User ID
Returns:
Google Calendar service object or None if not connected
"""
token_record = (
db.query(GoogleCalendarToken)
.filter(GoogleCalendarToken.user_id == user_id)
.first()
)
if not token_record:
return None
# Create credentials
creds = Credentials(
token=token_record.access_token,
refresh_token=token_record.refresh_token,
token_uri="https://oauth2.googleapis.com/token",
client_id=settings.google_client_id,
client_secret=settings.google_client_secret,
)
# Refresh if expired
if creds.expired and creds.refresh_token:
try:
creds.refresh(Request())
# Update tokens in DB
token_record.access_token = creds.token # type: ignore[assignment]
if creds.expiry:
token_record.token_expiry = creds.expiry # type: ignore[assignment]
db.commit()
except Exception as e:
print(f"Failed to refresh Google token: {e}")
return None
# Build service
try:
service = build("calendar", "v3", credentials=creds)
return service
except Exception as e:
print(f"Failed to build Google Calendar service: {e}")
return None
def create_calendar_event(
db: Session, booking: Booking, user_id: int
) -> Optional[str]:
"""
Create Google Calendar event for booking.
Args:
db: Database session
booking: Booking object
user_id: User ID
Returns:
Google Calendar event ID or None if failed
"""
try:
service = get_google_calendar_service(db, user_id)
if not service:
return None
# Create event
event = {
"summary": f"{booking.space.name}: {booking.title}",
"description": booking.description or "",
"start": {
"dateTime": booking.start_datetime.isoformat(), # type: ignore[union-attr]
"timeZone": "UTC",
},
"end": {
"dateTime": booking.end_datetime.isoformat(), # type: ignore[union-attr]
"timeZone": "UTC",
},
}
created_event = service.events().insert(calendarId="primary", body=event).execute()
return created_event.get("id")
except Exception as e:
print(f"Failed to create Google Calendar event: {e}")
return None
def update_calendar_event(
db: Session, booking: Booking, user_id: int, event_id: str
) -> bool:
"""
Update Google Calendar event for booking.
Args:
db: Database session
booking: Booking object
user_id: User ID
event_id: Google Calendar event ID
Returns:
True if successful, False otherwise
"""
try:
service = get_google_calendar_service(db, user_id)
if not service:
return False
# Update event
event = {
"summary": f"{booking.space.name}: {booking.title}",
"description": booking.description or "",
"start": {
"dateTime": booking.start_datetime.isoformat(), # type: ignore[union-attr]
"timeZone": "UTC",
},
"end": {
"dateTime": booking.end_datetime.isoformat(), # type: ignore[union-attr]
"timeZone": "UTC",
},
}
service.events().update(
calendarId="primary", eventId=event_id, body=event
).execute()
return True
except Exception as e:
print(f"Failed to update Google Calendar event: {e}")
return False
def delete_calendar_event(db: Session, event_id: str, user_id: int) -> bool:
"""
Delete Google Calendar event.
Args:
db: Database session
event_id: Google Calendar event ID
user_id: User ID
Returns:
True if successful, False otherwise
"""
try:
service = get_google_calendar_service(db, user_id)
if not service:
return False
service.events().delete(calendarId="primary", eventId=event_id).execute()
return True
except Exception as e:
print(f"Failed to delete Google Calendar event: {e}")
return False