from fastapi import APIRouter, Depends, HTTPException, status from sqlalchemy.orm import Session from app.database.connection import get_db from app.schemas.auth import UserCreate, UserLogin, UserResponse, TokenResponse from app.services.auth_service import AuthService from app.middleware.auth import get_current_user from app.database.models import User from app.utils.validators import validate_email, validate_password router = APIRouter(prefix="/api", tags=["auth"]) @router.post("/signup", response_model=TokenResponse, status_code=status.HTTP_201_CREATED) async def signup(user_data: UserCreate, db: Session = Depends(get_db)): """ Create a new user account. Args: user_data: User registration data db: Database session Returns: Access and refresh tokens with user info Raises: HTTPException: If email is invalid or already registered """ print(f"[SIGNUP] Received signup request for email: {user_data.email}") # Validate email if not validate_email(user_data.email): print(f"[SIGNUP] Invalid email format: {user_data.email}") raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail="Invalid email format" ) # Validate password is_valid, error_msg = validate_password(user_data.password) if not is_valid: print(f"[SIGNUP] Password validation failed: {error_msg}") raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail=error_msg ) try: # Create user print(f"[SIGNUP] Creating user...") user = AuthService.create_user( db=db, email=user_data.email, password=user_data.password, name=user_data.name ) print(f"[SIGNUP] User created successfully: {user.id}") # Generate tokens tokens = AuthService.generate_tokens(user) print(f"[SIGNUP] Tokens generated successfully") return TokenResponse( access_token=tokens["access_token"], refresh_token=tokens["refresh_token"], user=UserResponse.from_orm(user) ) except ValueError as e: print(f"[SIGNUP] ValueError: {str(e)}") raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail=str(e) ) except Exception as e: print(f"[SIGNUP] Unexpected error: {type(e).__name__}: {str(e)}") import traceback traceback.print_exc() raise HTTPException( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail="An error occurred during signup" ) @router.post("/login", response_model=TokenResponse) async def login(credentials: UserLogin, db: Session = Depends(get_db)): """ Authenticate user and return tokens. Args: credentials: User login credentials db: Database session Returns: Access and refresh tokens with user info Raises: HTTPException: If credentials are invalid """ # Authenticate user user = AuthService.authenticate_user( db=db, email=credentials.email, password=credentials.password ) if not user: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="Incorrect email or password" ) # Generate tokens tokens = AuthService.generate_tokens(user) return TokenResponse( access_token=tokens["access_token"], refresh_token=tokens["refresh_token"], user=UserResponse.from_orm(user) ) @router.get("/check-auth", response_model=UserResponse) async def check_auth(current_user: User = Depends(get_current_user)): """ Verify authentication token and return user info. Args: current_user: Current authenticated user Returns: User information Raises: HTTPException: If token is invalid or expired """ return UserResponse.from_orm(current_user) @router.post("/auth/google", response_model=TokenResponse) async def google_auth( request: dict, db: Session = Depends(get_db) ): """ Authenticate user with Google OAuth and return JWT tokens. Args: request: Dictionary with 'credential' field (Google JWT token) db: Database session Returns: Access and refresh JWT tokens with user info Raises: HTTPException: If Google token is invalid """ from app.config.settings import settings print(f"[GOOGLE AUTH] Received Google OAuth request") try: credential = request.get("credential") if not credential: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail="Google credential is required" ) print(f"[GOOGLE AUTH] Verifying Google token...") # Verify Google token and get user info google_data = await AuthService.verify_google_token( credential=credential, client_id=settings.GOOGLE_CLIENT_ID ) print(f"[GOOGLE AUTH] Token verified for email: {google_data['email']}") # Create or get user user = AuthService.create_user_from_google( db=db, google_id=google_data["google_id"], email=google_data["email"], name=google_data.get("name") ) print(f"[GOOGLE AUTH] User created/retrieved: {user.id}") # Generate JWT tokens (same as email/password login) tokens = AuthService.generate_tokens(user) print(f"[GOOGLE AUTH] JWT tokens generated successfully") return TokenResponse( access_token=tokens["access_token"], refresh_token=tokens["refresh_token"], user=UserResponse.from_orm(user) ) except ValueError as e: print(f"[GOOGLE AUTH] ValueError: {str(e)}") raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail=str(e) ) except Exception as e: print(f"[GOOGLE AUTH] Unexpected error: {type(e).__name__}: {str(e)}") import traceback traceback.print_exc() raise HTTPException( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail="Failed to authenticate with Google" )