""" FastAPI dependency helpers for authenticated member access. Member tokens carry role='member' in the JWT payload. """ import uuid from fastapi import Depends, HTTPException, status from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer from jose import JWTError from sqlalchemy import select from sqlalchemy.ext.asyncio import AsyncSession from app.auth.jwt import verify_access_token from app.database import get_db from app.models.member import Member bearer_scheme = HTTPBearer() async def _get_member_from_token( credentials: HTTPAuthorizationCredentials, db: AsyncSession, ) -> Member: credentials_exception = HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="Could not validate credentials", headers={"WWW-Authenticate": "Bearer"}, ) try: payload = verify_access_token(credentials.credentials) if payload.get("role") != "member": raise credentials_exception member_id: str = payload.get("sub") if member_id is None: raise credentials_exception member_uuid = uuid.UUID(member_id) except (JWTError, ValueError): raise credentials_exception result = await db.execute(select(Member).where(Member.id == member_uuid)) member = result.scalars().first() if member is None: raise credentials_exception if not member.is_active: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="Inactive member account", ) return member async def get_authenticated_member( credentials: HTTPAuthorizationCredentials = Depends(bearer_scheme), db: AsyncSession = Depends(get_db), ) -> Member: return await _get_member_from_token(credentials, db) async def get_current_member( member: Member = Depends(get_authenticated_member), ) -> Member: if member.member_status != "active": raise HTTPException( status_code=status.HTTP_403_FORBIDDEN, detail="Member onboarding is not complete.", ) return member