zohaibcodez's picture
initial deploy
ce4fddb
Raw
History Blame Contribute Delete
5.68 kB
"""Authentication endpoints — register, login, get current user."""
from __future__ import annotations
from fastapi import APIRouter, HTTPException, status, Depends
from app.models.schemas import (
AuthResponse,
LoginRequest,
ProfileUpdateRequest,
RegisterRequest,
SettingsUpdateRequest,
UserProfile,
)
from app.services.auth_service import hash_password, verify_password, create_access_token, get_current_user_id, get_current_user
from app.utils.supabase_client import get_anon_client, get_profile, insert_profile, update_profile
router = APIRouter(prefix="/auth", tags=["auth"])
@router.post("/register", response_model=AuthResponse)
async def register(req: RegisterRequest):
"""Register a new user account."""
client = get_anon_client()
try:
# Create user in Supabase Auth
auth_response = client.auth.sign_up({
"email": req.email,
"password": req.password,
})
if not auth_response.user:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail="Registration failed. Email may already be in use.",
)
user_id = auth_response.user.id
# Create profile record manually in the backend
insert_profile(user_id, req.full_name, req.role)
# Generate JWT
token = create_access_token(user_id, req.email)
return AuthResponse(
access_token=token,
user=UserProfile(
id=user_id,
email=req.email,
full_name=req.full_name,
role=req.role,
),
)
except HTTPException:
raise
except Exception as e:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=f"Registration failed: {str(e)}",
)
@router.post("/login", response_model=AuthResponse)
async def login(req: LoginRequest):
"""Sign in with email and password."""
client = get_anon_client()
try:
auth_response = client.auth.sign_in_with_password({
"email": req.email,
"password": req.password,
})
if not auth_response.user:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Invalid email or password.",
)
user_id = auth_response.user.id
# Fetch profile
profile = get_profile(user_id)
# Generate JWT
token = create_access_token(user_id, req.email)
return AuthResponse(
access_token=token,
user=UserProfile(
id=user_id,
email=req.email,
full_name=profile.get("full_name", "User") if profile else "User",
role=profile.get("role", "Medical Student") if profile else "Medical Student",
avatar_url=profile.get("avatar_url") if profile else None,
settings=profile.get("settings", {}) if profile else {},
created_at=profile.get("created_at") if profile else None,
),
)
except HTTPException:
raise
except Exception as e:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail=f"Login failed: {str(e)}",
)
@router.get("/me", response_model=UserProfile)
async def get_me(current_user: dict = Depends(get_current_user)):
"""Get current authenticated user's profile."""
profile = get_profile(current_user["id"])
if not profile:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail="Profile not found.",
)
return UserProfile(
id=profile["id"],
email=current_user["email"], # email comes from JWT, not profiles table
full_name=profile.get("full_name", "User"),
role=profile.get("role", "Medical Student"),
avatar_url=profile.get("avatar_url"),
settings=profile.get("settings", {}),
created_at=profile.get("created_at"),
)
@router.patch("/profile", response_model=UserProfile)
async def update_me(req: ProfileUpdateRequest, current_user: dict = Depends(get_current_user)):
"""Update current authenticated user's profile."""
updates = req.model_dump(exclude_unset=True, exclude_none=True)
profile = update_profile(current_user["id"], updates) if updates else get_profile(current_user["id"])
if not profile:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Profile not found.")
return UserProfile(
id=profile["id"],
email=current_user["email"],
full_name=profile.get("full_name", "User"),
role=profile.get("role", "Medical Student"),
avatar_url=profile.get("avatar_url"),
settings=profile.get("settings", {}),
created_at=profile.get("created_at"),
)
@router.patch("/settings", response_model=UserProfile)
async def update_settings(req: SettingsUpdateRequest, current_user: dict = Depends(get_current_user)):
"""Persist current user's UI/analysis settings."""
profile = update_profile(current_user["id"], {"settings": req.settings})
if not profile:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Profile not found.")
return UserProfile(
id=profile["id"],
email=current_user["email"],
full_name=profile.get("full_name", "User"),
role=profile.get("role", "Medical Student"),
avatar_url=profile.get("avatar_url"),
settings=profile.get("settings", {}),
created_at=profile.get("created_at"),
)