102 lines
3.7 KiB
Python
102 lines
3.7 KiB
Python
"""Calendar service — unified interface for Google, Yandex, Apple CalDAV.
|
|
|
|
Manages calendar provider connections and event creation.
|
|
"""
|
|
|
|
import json
|
|
import logging
|
|
from datetime import datetime, timedelta, timezone
|
|
from typing import Any, Optional
|
|
from uuid import UUID
|
|
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
|
|
from app.models.user import User
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
CALENDAR_PROVIDERS = ("google", "yandex", "apple")
|
|
|
|
|
|
class CalendarService:
|
|
def __init__(self, db: AsyncSession):
|
|
self.db = db
|
|
|
|
async def get_calendar_credentials(self, user: User) -> Optional[dict[str, Any]]:
|
|
"""Get stored calendar credentials for user."""
|
|
if not hasattr(user, "calendar_provider") or not user.calendar_provider:
|
|
return None
|
|
if not hasattr(user, "calendar_credentials") or not user.calendar_credentials:
|
|
return None
|
|
try:
|
|
return json.loads(user.calendar_credentials)
|
|
except (json.JSONDecodeError, TypeError):
|
|
return None
|
|
|
|
async def set_calendar_credentials(
|
|
self, user: User, provider: str, credentials: dict[str, Any]
|
|
) -> None:
|
|
user.calendar_provider = provider
|
|
user.calendar_credentials = json.dumps(credentials)
|
|
await self.db.commit()
|
|
|
|
async def disconnect_calendar(self, user: User) -> None:
|
|
user.calendar_provider = None
|
|
user.calendar_credentials = None
|
|
await self.db.commit()
|
|
|
|
def _get_client(self, provider: str, credentials: dict[str, Any]):
|
|
"""Get appropriate calendar client for provider."""
|
|
if provider == "google":
|
|
from app.integrations.calendar.google_calendar import GoogleCalendarClient
|
|
return GoogleCalendarClient(access_token=credentials.get("access_token", ""))
|
|
elif provider == "yandex":
|
|
from app.integrations.calendar.yandex_calendar import YandexCalendarClient
|
|
return YandexCalendarClient(access_token=credentials.get("access_token", ""))
|
|
elif provider == "apple":
|
|
from app.integrations.calendar.apple_caldav import AppleCalDavStub
|
|
return AppleCalDavStub()
|
|
raise ValueError(f"Unknown calendar provider: {provider}")
|
|
|
|
async def create_idea_event(self, user: User, idea_title: str, idea_content: str) -> bool:
|
|
"""Create a calendar event from an idea."""
|
|
creds = await self.get_calendar_credentials(user)
|
|
if not creds:
|
|
logger.warning("No calendar credentials for user %s", user.id)
|
|
return False
|
|
|
|
provider = user.calendar_provider
|
|
if not provider:
|
|
return False
|
|
|
|
client = self._get_client(provider, creds)
|
|
|
|
now = datetime.now(timezone.utc)
|
|
start_iso = now.isoformat()
|
|
end_iso = (now + timedelta(hours=1)).isoformat()
|
|
|
|
return await client.create_event(
|
|
summary=f"Idea: {idea_title[:100]}",
|
|
description=idea_content[:1000],
|
|
start_iso=start_iso,
|
|
end_iso=end_iso,
|
|
)
|
|
|
|
async def list_events(self, user: User, max_results: int = 10) -> list[dict]:
|
|
creds = await self.get_calendar_credentials(user)
|
|
if not creds or not user.calendar_provider:
|
|
return []
|
|
|
|
client = self._get_client(user.calendar_provider, creds)
|
|
return await client.list_events(max_results=max_results)
|
|
|
|
async def health_check(self, user: User) -> bool:
|
|
creds = await self.get_calendar_credentials(user)
|
|
if not creds or not user.calendar_provider:
|
|
return False
|
|
try:
|
|
client = self._get_client(user.calendar_provider, creds)
|
|
return await client.health_check()
|
|
except Exception:
|
|
return False
|