Files

79 lines
2.8 KiB
Python

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,
)