from fastapi import Request, Depends, HTTPException, status from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy.future import select from datetime import datetime, timedelta, timezone from app.database import get_db from app import models from app.utils.auth import verify_supabase_jwt async def get_current_user(request: Request, db: AsyncSession = Depends(get_db)) -> models.User: session_cookie = request.cookies.get("archvise_session") # Fallback to Authorization header if cookie is missing (e.g. cross-domain/proxy environment) if not session_cookie: auth_header = request.headers.get("Authorization") if auth_header and auth_header.startswith("Bearer "): session_cookie = auth_header.split(" ")[1] if not session_cookie: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="Not authenticated" ) try: # Guest session: token starts with 'guest_' prefix — look up uid from Redis (async) if session_cookie.startswith("guest_"): import redis.asyncio as redis_async from app.config import settings as cfg try: r = redis_async.Redis.from_url(cfg.REDIS_URL, decode_responses=True) guest_uid = await r.get(f"guest_session:{session_cookie}") await r.aclose() except Exception: guest_uid = None if not guest_uid: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="Guest session expired. Please start a new session." ) decoded_claims = { "uid": guest_uid, "email": f"{guest_uid}@guest.archvise.com", "name": "Archvise Guest", "picture": None } else: # Verify Supabase JWT Offline decoded_claims = verify_supabase_jwt(session_cookie) except HTTPException: raise except Exception as e: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="Session expired or invalid" ) firebase_uid = decoded_claims.get("uid") email = decoded_claims.get("email") name = decoded_claims.get("name") avatar_url = decoded_claims.get("picture") # Query database for user result = await db.execute(select(models.User).where(models.User.firebase_uid == firebase_uid)) user = result.scalars().first() if not user: # Seamless registration: Create new user if not found in db user = models.User( firebase_uid=firebase_uid, email=email, name=name, avatar_url=avatar_url, plan="free", display_mode="founder", credits_remaining=2, credits_reset_at=datetime.now(timezone.utc) + timedelta(days=30), is_active=True ) db.add(user) await db.commit() await db.refresh(user) # Check if monthly credits need to be reset (timezone-aware comparison) now_utc = datetime.now(timezone.utc) reset_at = user.credits_reset_at # Ensure reset_at is timezone-aware for comparison if reset_at and reset_at.tzinfo is None: reset_at = reset_at.replace(tzinfo=timezone.utc) if reset_at and now_utc > reset_at: if user.plan == "pro": user.credits_remaining = -1 # -1 = unlimited elif user.plan == "starter": user.credits_remaining = 15 else: user.credits_remaining = 2 user.credits_reset_at = now_utc + timedelta(days=30) db.add(user) await db.commit() if not user.is_active: raise HTTPException( status_code=status.HTTP_403_FORBIDDEN, detail="User account is deactivated" ) return user