Files
voidea/app/services/calendar_service.py
T

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