ryanxely's picture
KPI extraction
9b0ce22
Raw
History Blame Contribute Delete
8.61 kB
from fastapi import APIRouter, HTTPException, Depends, Header
from typing import Optional
from api.models.schemas import (
UserRegistration, UserCredentials, UserProfileUpdate,
PasswordChange, TokenResponse, AuthResponse, UserProfile,
Conversation, ConversationDetail
)
from api.services.auth_service import auth_service
router = APIRouter(tags=["auth"])
# ── Dependency for protected routes ────────────────────────────────────────────
def get_current_user(authorization: Optional[str] = Header(None)):
"""Extract user from JWT token"""
if not authorization:
raise HTTPException(status_code=401, detail="Missing authorization header")
try:
scheme, token = authorization.split()
if scheme.lower() != "bearer":
raise HTTPException(status_code=401, detail="Invalid auth scheme")
except ValueError:
raise HTTPException(status_code=401, detail="Invalid authorization header")
payload = auth_service.verify_token(token)
if not payload:
raise HTTPException(status_code=401, detail="Invalid or expired token")
return payload
# ────────────────────────────────────────────────────────────────────────────────
# PUBLIC ENDPOINTS
# ────────────────────────────────────────────────────────────────────────────────
@router.post("/register", response_model=AuthResponse)
async def register(user_data: UserRegistration):
"""Register new user"""
success, message, user_id = auth_service.register_user(
email=user_data.email,
password=user_data.password,
full_name=user_data.full_name,
dob=user_data.dob,
sex=user_data.sex,
medical_history=user_data.medical_history,
geolocation=user_data.geolocation
)
if not success:
raise HTTPException(status_code=400, detail=message)
return AuthResponse(
success=True,
message=message,
data={"user_id": user_id}
)
@router.post("/login", response_model=TokenResponse)
async def login(credentials: UserCredentials):
"""Login user and return JWT token"""
success, message, user_data = auth_service.login_user(
email=credentials.email,
password=credentials.password
)
if not success:
raise HTTPException(status_code=401, detail=message)
access_token = auth_service.create_access_token(
user_id=user_data["user_id"],
email=user_data["email"]
)
return TokenResponse(
access_token=access_token,
user=UserProfile(**user_data)
)
# ────────────────────────────────────────────────────────────────────────────────
# PROTECTED ENDPOINTS
# ────────────────────────────────────────────────────────────────────────────────
@router.get("/profile", response_model=UserProfile)
async def get_profile(current_user=Depends(get_current_user)):
"""Get current user profile"""
user_data = auth_service.get_user_by_id(current_user["sub"])
if not user_data:
raise HTTPException(status_code=404, detail="User not found")
return UserProfile(**user_data)
@router.put("/profile", response_model=AuthResponse)
async def update_profile(
profile_data: UserProfileUpdate,
current_user=Depends(get_current_user)
):
"""Update user profile"""
success, message = auth_service.update_user_profile(
user_id=current_user["sub"],
email=profile_data.email,
full_name=profile_data.full_name,
dob=profile_data.dob,
sex=profile_data.sex,
medical_history=profile_data.medical_history,
geolocation=profile_data.geolocation
)
if not success:
raise HTTPException(status_code=400, detail=message)
return AuthResponse(success=True, message=message)
@router.post("/change-password", response_model=AuthResponse)
async def change_password(
pwd_change: PasswordChange,
current_user=Depends(get_current_user)
):
"""Change user password"""
success, message = auth_service.change_password(
user_id=current_user["sub"],
old_password=pwd_change.old_password,
new_password=pwd_change.new_password
)
if not success:
raise HTTPException(status_code=400, detail=message)
return AuthResponse(success=True, message=message)
@router.delete("/account", response_model=AuthResponse)
async def delete_account(
password: str,
current_user=Depends(get_current_user)
):
"""Delete user account"""
success, message = auth_service.delete_user(
user_id=current_user["sub"],
password=password
)
if not success:
raise HTTPException(status_code=400, detail=message)
return AuthResponse(success=True, message=message)
# ────────────────────────────────────────────────────────────────────────────────
# CONVERSATION ENDPOINTS
# ────────────────────────────────────────────────────────────────────────────────
@router.post("/conversations", response_model=AuthResponse)
async def create_conversation(
title: Optional[str] = None,
current_user=Depends(get_current_user)
):
"""Create new conversation"""
success, message, conversation_id = auth_service.create_conversation(
user_id=current_user["sub"],
title=title or "New Conversation"
)
if not success:
raise HTTPException(status_code=400, detail=message)
return AuthResponse(
success=True,
message=message,
data={"conversation_id": conversation_id}
)
@router.get("/conversations", response_model=dict)
async def get_conversations(current_user=Depends(get_current_user)):
"""Get all user conversations"""
success, message, conversations = auth_service.get_conversations(current_user["sub"])
if not success:
raise HTTPException(status_code=400, detail=message)
return {
"success": True,
"message": message,
"conversations": conversations
}
@router.delete("/conversations/{conversation_id}", response_model=AuthResponse)
async def delete_conversation(
conversation_id: str,
current_user=Depends(get_current_user)
):
"""Delete conversation"""
success, message = auth_service.delete_conversation(
user_id=current_user["sub"],
conversation_id=conversation_id
)
if not success:
raise HTTPException(status_code=400, detail=message)
return AuthResponse(success=True, message=message)
@router.get("/conversations/{conversation_id}")
async def get_conversation_detail(
conversation_id: str,
current_user=Depends(get_current_user)
):
"""Get conversation detail with all messages and diagnosis"""
from api.services.database_interface import conversation_db
conv_data = auth_service._load_conversation(current_user["sub"], conversation_id)
if not conv_data:
raise HTTPException(status_code=404, detail="Conversation not found")
# Load messages from JSONL
messages = conversation_db.get_conversation_messages(
current_user["sub"],
conversation_id
)
# Load diagnosis if exists
diagnosis_data = conversation_db.get_diagnosis_from_conversation(
current_user["sub"],
conversation_id
)
return {
"conversation_id": conversation_id,
"title": conv_data.get("title"),
"created_at": conv_data.get("created_at"),
"messages": messages,
"diagnosis": diagnosis_data.get("diagnosis") if diagnosis_data else None,
"recommendations": diagnosis_data.get("recommendations") if diagnosis_data else None
}