import os from typing import Optional import httpx from fastapi import Depends, HTTPException, Request from fastapi.responses import RedirectResponse from sqlmodel import Session, select from app.database import get_session from app.models import User TWITCH_CLIENT_ID = os.getenv("TWITCH_CLIENT_ID", "") TWITCH_CLIENT_SECRET = os.getenv("TWITCH_CLIENT_SECRET", "") TWITCH_REDIRECT_URI = os.getenv("TWITCH_REDIRECT_URI", "http://localhost:8000/auth/callback") SCOPES = "channel:read:subscriptions bits:read channel:read:redemptions moderator:read:followers" TWITCH_AUTH_URL = ( "https://id.twitch.tv/oauth2/authorize" f"?client_id={TWITCH_CLIENT_ID}" f"&redirect_uri={TWITCH_REDIRECT_URI}" "&response_type=code" f"&scope={SCOPES.replace(' ', '+')}" ) async def exchange_code(code: str) -> dict: async with httpx.AsyncClient() as client: r = await client.post("https://id.twitch.tv/oauth2/token", data={ "client_id": TWITCH_CLIENT_ID, "client_secret": TWITCH_CLIENT_SECRET, "code": code, "grant_type": "authorization_code", "redirect_uri": TWITCH_REDIRECT_URI, }) r.raise_for_status() return r.json() async def get_twitch_user(access_token: str) -> dict: async with httpx.AsyncClient() as client: r = await client.get( "https://api.twitch.tv/helix/users", headers={"Authorization": f"Bearer {access_token}", "Client-Id": TWITCH_CLIENT_ID}, ) r.raise_for_status() return r.json()["data"][0] def get_current_user(request: Request, session: Session = Depends(get_session)) -> Optional[User]: user_id = request.session.get("user_id") if not user_id: return None return session.get(User, user_id) def require_user(request: Request, session: Session = Depends(get_session)) -> User: user_id = request.session.get("user_id") if not user_id: raise HTTPException(status_code=307, headers={"Location": "/auth/login"}) user = session.get(User, user_id) if not user: raise HTTPException(status_code=307, headers={"Location": "/auth/login"}) return user