first prototype commit
This commit is contained in:
@@ -0,0 +1,113 @@
|
||||
from fastapi import APIRouter, Depends, HTTPException, status, Header
|
||||
from sqlalchemy.orm import Session
|
||||
from backend.database import get_db
|
||||
from backend.models import User, UserRole
|
||||
from backend.schemas import UserOut, GoogleAuthRequest, DemoLoginRequest
|
||||
from backend.config import create_access_token, decode_access_token, GOOGLE_CLIENT_ID
|
||||
from typing import Optional
|
||||
from google.oauth2 import id_token
|
||||
from google.auth.transport import requests as google_requests
|
||||
|
||||
router = APIRouter(prefix="/api/auth", tags=["auth"])
|
||||
|
||||
def get_current_user(authorization: Optional[str] = Header(None), db: Session = Depends(get_db)) -> User:
|
||||
if not authorization:
|
||||
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Missing authorization header")
|
||||
|
||||
parts = authorization.split()
|
||||
if len(parts) != 2 or parts[0].lower() != "bearer":
|
||||
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid authorization header format")
|
||||
|
||||
token = parts[1]
|
||||
payload = decode_access_token(token)
|
||||
if not payload or "sub" not in payload:
|
||||
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid or expired token")
|
||||
|
||||
user_id = int(payload["sub"])
|
||||
user = db.query(User).filter(User.id == user_id, User.is_active == True).first()
|
||||
if not user:
|
||||
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="User not found or inactive")
|
||||
|
||||
return user
|
||||
|
||||
def get_admin_user(current_user: User = Depends(get_current_user)) -> User:
|
||||
if current_user.role != UserRole.ADMIN.value:
|
||||
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="Admin privileges required")
|
||||
return current_user
|
||||
|
||||
@router.post("/google")
|
||||
def google_auth(req: GoogleAuthRequest, db: Session = Depends(get_db)):
|
||||
email = req.email
|
||||
name = req.name or "Google User"
|
||||
avatar_url = req.avatar_url or f"https://api.dicebear.com/7.x/bottts/svg?seed={email}"
|
||||
google_sub = None
|
||||
|
||||
# Try verifying real Google token if client ID configured and credential provided
|
||||
if req.credential and len(req.credential) > 50:
|
||||
try:
|
||||
if GOOGLE_CLIENT_ID:
|
||||
id_info = id_token.verify_oauth2_token(req.credential, google_requests.Request(), GOOGLE_CLIENT_ID)
|
||||
else:
|
||||
id_info = id_token.verify_oauth2_token(req.credential, google_requests.Request())
|
||||
email = id_info.get("email", email)
|
||||
name = id_info.get("name", name)
|
||||
avatar_url = id_info.get("picture", avatar_url)
|
||||
google_sub = id_info.get("sub")
|
||||
except Exception as e:
|
||||
# Fallback to provided details if token decode fails in dev
|
||||
if not email:
|
||||
raise HTTPException(status_code=400, detail=f"Google token verification failed: {str(e)}")
|
||||
|
||||
if not email:
|
||||
raise HTTPException(status_code=400, detail="Email is required")
|
||||
|
||||
user = db.query(User).filter(User.email == email).first()
|
||||
|
||||
# Check if this is the first user ever registered
|
||||
total_users = db.query(User).count()
|
||||
initial_role = UserRole.ADMIN.value if total_users == 0 else UserRole.REGULAR.value
|
||||
|
||||
if not user:
|
||||
user = User(
|
||||
email=email,
|
||||
name=name,
|
||||
avatar_url=avatar_url,
|
||||
google_id=google_sub,
|
||||
role=initial_role,
|
||||
weekly_star_quota=15
|
||||
)
|
||||
db.add(user)
|
||||
db.commit()
|
||||
db.refresh(user)
|
||||
else:
|
||||
# Update existing user google_id or default avatar if missing
|
||||
if google_sub and not user.google_id:
|
||||
user.google_id = google_sub
|
||||
if avatar_url and not user.avatar_url:
|
||||
user.avatar_url = avatar_url
|
||||
db.commit()
|
||||
db.refresh(user)
|
||||
|
||||
token = create_access_token({"sub": str(user.id), "email": user.email, "role": user.role})
|
||||
return {
|
||||
"access_token": token,
|
||||
"token_type": "bearer",
|
||||
"user": UserOut.model_validate(user)
|
||||
}
|
||||
|
||||
@router.post("/demo-login")
|
||||
def demo_login(req: DemoLoginRequest, db: Session = Depends(get_db)):
|
||||
user = db.query(User).filter(User.email == req.email).first()
|
||||
if not user:
|
||||
raise HTTPException(status_code=404, detail="Demo user not found. Run backend initialization first.")
|
||||
|
||||
token = create_access_token({"sub": str(user.id), "email": user.email, "role": user.role})
|
||||
return {
|
||||
"access_token": token,
|
||||
"token_type": "bearer",
|
||||
"user": UserOut.model_validate(user)
|
||||
}
|
||||
|
||||
@router.get("/me", response_model=UserOut)
|
||||
def get_me(current_user: User = Depends(get_current_user)):
|
||||
return current_user
|
||||
Reference in New Issue
Block a user