add google calendar connector route

This commit is contained in:
CREDO23 2025-08-02 01:41:41 +02:00
parent f96afe0e2a
commit 1c9f857d00
3 changed files with 133 additions and 23 deletions

View file

@ -2,6 +2,7 @@ from fastapi import APIRouter
from .chats_routes import router as chats_router from .chats_routes import router as chats_router
from .documents_routes import router as documents_router from .documents_routes import router as documents_router
from .google_calendar_add_connector_route import router as google_oauth_router
from .llm_config_routes import router as llm_config_router from .llm_config_routes import router as llm_config_router
from .logs_routes import router as logs_router from .logs_routes import router as logs_router
from .podcasts_routes import router as podcasts_router from .podcasts_routes import router as podcasts_router
@ -15,5 +16,6 @@ router.include_router(documents_router)
router.include_router(podcasts_router) router.include_router(podcasts_router)
router.include_router(chats_router) router.include_router(chats_router)
router.include_router(search_source_connectors_router) router.include_router(search_source_connectors_router)
router.include_router(google_oauth_router)
router.include_router(llm_config_router) router.include_router(llm_config_router)
router.include_router(logs_router) router.include_router(logs_router)

View file

@ -2,16 +2,19 @@
import base64 import base64
import json import json
from sqlite3 import IntegrityError
from uuid import UUID from uuid import UUID
from venv import logger
from fastapi import APIRouter, Depends, HTTPException, Request from fastapi import APIRouter, Depends, HTTPException, Request
from fastapi.responses import RedirectResponse from fastapi.responses import RedirectResponse
from google_auth_oauthlib.flow import Flow from google_auth_oauthlib.flow import Flow
from jsonschema import ValidationError
from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.future import select from sqlalchemy.future import select
from app.config import config from app.config import config
from app.db import GoogleCalendarAccount, User, get_async_session from app.db import SearchSourceConnector, User, get_async_session
from app.users import current_active_user from app.users import current_active_user
router = APIRouter() router = APIRouter()
@ -41,7 +44,7 @@ def get_google_flow():
) from e ) from e
@router.get("/auth/google/calendar/connector/init/") @router.get("/auth/google/calendar/connector/add/")
async def connect_calendar(space_id: int, user: User = Depends(current_active_user)): async def connect_calendar(space_id: int, user: User = Depends(current_active_user)):
try: try:
if not space_id: if not space_id:
@ -90,31 +93,57 @@ async def calendar_callback(
flow.fetch_token(code=code) flow.fetch_token(code=code)
creds = flow.credentials creds = flow.credentials
token = creds.token creds_dict = json.loads(creds.to_json())
refresh_token = creds.refresh_token
existing = await session.scalar( try:
select(GoogleCalendarAccount).where( # Check if a connector with the same type already exists for this user
GoogleCalendarAccount.user_id == user_id result = await session.execute(
) select(SearchSourceConnector).filter(
) SearchSourceConnector.user_id == user_id,
if existing: SearchSourceConnector.connector_type == "GOOGLE_CALENDAR_CONNECTOR",
existing.access_token = token
existing.refresh_token = refresh_token or existing.refresh_token
else:
session.add(
GoogleCalendarAccount(
user_id=user_id,
access_token=token,
refresh_token=refresh_token,
) )
) )
existing_connector = result.scalars().first()
if existing_connector:
raise HTTPException(
status_code=409,
detail="A GOOGLE_CALENDAR_CONNECTOR connector already exists. Each user can have only one connector of each type.",
)
db_connector = SearchSourceConnector(
name="Google Calendar Connector",
connector_type="GOOGLE_CALENDAR_CONNECTOR",
config=creds_dict,
user_id=user_id,
is_indexable=True,
)
session.add(db_connector)
await session.commit()
await session.refresh(db_connector)
return RedirectResponse(
f"{config.NEXT_FRONTEND_URL}/dashboard/{space_id}/connectors/add/google-calendar-connector?success=true"
)
except ValidationError as e:
await session.rollback()
raise HTTPException(
status_code=422, detail=f"Validation error: {e!s}"
) from e
except IntegrityError as e:
await session.rollback()
raise HTTPException(
status_code=409,
detail=f"Integrity error: A connector with this type already exists. {e!s}",
) from e
except HTTPException:
await session.rollback()
raise
except Exception as e:
logger.error(f"Failed to create search source connector: {e!s}")
await session.rollback()
raise HTTPException(
status_code=500,
detail=f"Failed to create search source connector: {e!s}",
) from e
await session.commit()
return RedirectResponse(
f"{config.NEXT_FRONTEND_URL}/dashboard/{space_id}/connectors/add/google-calendar-connector?success=true"
)
except Exception as e: except Exception as e:
raise HTTPException( raise HTTPException(
status_code=500, detail=f"Failed to complete Google OAuth: {e!s}" status_code=500, detail=f"Failed to complete Google OAuth: {e!s}"

View file

@ -40,6 +40,7 @@ from app.tasks.connectors_indexing_tasks import (
index_confluence_pages, index_confluence_pages,
index_discord_messages, index_discord_messages,
index_github_repos, index_github_repos,
index_google_calendar_events,
index_jira_issues, index_jira_issues,
index_linear_issues, index_linear_issues,
index_notion_pages, index_notion_pages,
@ -489,6 +490,24 @@ async def index_connector_content(
) )
response_message = "ClickUp indexing started in the background." response_message = "ClickUp indexing started in the background."
elif (
connector.connector_type
== SearchSourceConnectorType.GOOGLE_CALENDAR_CONNECTOR
):
# Run indexing in background
logger.info(
f"Triggering Google Calendar indexing for connector {connector_id} into search space {search_space_id} from {indexing_from} to {indexing_to}"
)
background_tasks.add_task(
run_google_calendar_indexing_with_new_session,
connector_id,
search_space_id,
str(user.id),
indexing_from,
indexing_to,
)
response_message = "Google Calendar indexing started in the background."
elif connector.connector_type == SearchSourceConnectorType.DISCORD_CONNECTOR: elif connector.connector_type == SearchSourceConnectorType.DISCORD_CONNECTOR:
# Run indexing in background # Run indexing in background
logger.info( logger.info(
@ -1034,3 +1053,63 @@ async def run_clickup_indexing(
exc_info=True, exc_info=True,
) )
# Optionally update status in DB to indicate failure # Optionally update status in DB to indicate failure
# Add new helper functions for Google Calendar indexing
async def run_google_calendar_indexing_with_new_session(
connector_id: int,
search_space_id: int,
user_id: str,
start_date: str,
end_date: str,
):
"""Wrapper to run Google Calendar indexing with its own database session."""
logger.info(
f"Background task started: Indexing Google Calendar connector {connector_id} into space {search_space_id} from {start_date} to {end_date}"
)
async with async_session_maker() as session:
await run_google_calendar_indexing(
session, connector_id, search_space_id, user_id, start_date, end_date
)
logger.info(
f"Background task finished: Indexing Google Calendar connector {connector_id}"
)
async def run_google_calendar_indexing(
session: AsyncSession,
connector_id: int,
search_space_id: int,
user_id: str,
start_date: str,
end_date: str,
):
"""Runs the Google Calendar indexing task and updates the timestamp."""
try:
indexed_count, error_message = await index_google_calendar_events(
session,
connector_id,
search_space_id,
user_id,
start_date,
end_date,
update_last_indexed=False,
)
if error_message:
logger.error(
f"Google Calendar indexing failed for connector {connector_id}: {error_message}"
)
# Optionally update status in DB to indicate failure
else:
logger.info(
f"Google Calendar indexing successful for connector {connector_id}. Indexed {indexed_count} documents."
)
# Update the last indexed timestamp only on success
await update_connector_last_indexed(session, connector_id)
await session.commit() # Commit timestamp update
except Exception as e:
logger.error(
f"Critical error in run_google_calendar_indexing for connector {connector_id}: {e}",
exc_info=True,
)
# Optionally update status in DB to indicate failure