import logging from fastapi import APIRouter, Depends, Request, status from fastapi.responses import PlainTextResponse, RedirectResponse, Response from sqlalchemy.orm import Session from app.config import Settings from app.dependencies import ( get_app_settings, get_auth_db, get_current_auth_session, get_ticktick_client, ) from app.integrations.ticktick import TickTickAuthError, TickTickClient, TickTickConfigError, TickTickRequestError from app.services.auth import AuthenticatedSession from app.services.config_page import save_config_value router = APIRouter(tags=["ticktick"]) logger = logging.getLogger(__name__) @router.get("/ticktick/auth/start") def start_ticktick_auth( current_auth: AuthenticatedSession | None = Depends(get_current_auth_session), ticktick_client: TickTickClient = Depends(get_ticktick_client), ) -> Response: if current_auth is None: return RedirectResponse(url="/login", status_code=status.HTTP_303_SEE_OTHER) try: authorization_url = ticktick_client.build_authorization_url() except TickTickConfigError as exc: logger.warning("Rejected TickTick OAuth start due to incomplete configuration: %s", exc) return PlainTextResponse("TickTick integration is not configured", status_code=400) return RedirectResponse(url=authorization_url, status_code=status.HTTP_303_SEE_OTHER) @router.get("/ticktick/auth/code") def handle_ticktick_auth_code( request: Request, auth_db_session: Session = Depends(get_auth_db), settings: Settings = Depends(get_app_settings), ticktick_client: TickTickClient = Depends(get_ticktick_client), ) -> Response: code = request.query_params.get("code", "") state = request.query_params.get("state", "") if not code or not state: return RedirectResponse( url="/config?ticktick_oauth=invalid-callback", status_code=status.HTTP_303_SEE_OTHER, ) try: token = ticktick_client.exchange_authorization_code(code=code, state=state) save_config_value( auth_db_session, env_name="TICKTICK_TOKEN", value=token, bootstrap_settings=settings, ) except TickTickAuthError as exc: logger.warning("Rejected TickTick OAuth callback due to invalid state: %s", exc) return RedirectResponse( url="/config?ticktick_oauth=invalid-state", status_code=status.HTTP_303_SEE_OTHER, ) except (TickTickConfigError, TickTickRequestError, ValueError) as exc: logger.warning("TickTick OAuth callback failed: %s", exc) return RedirectResponse( url="/config?ticktick_oauth=failed", status_code=status.HTTP_303_SEE_OTHER, ) return RedirectResponse( url="/config?ticktick_oauth=success", status_code=status.HTTP_303_SEE_OTHER, )