from datetime import timedelta from fastapi import Depends, FastAPI, HTTPException, status from fastapi.middleware.cors import CORSMiddleware from sqlalchemy import select from sqlalchemy.ext.asyncio import AsyncSession from services.user_service.models import User from services.user_service.schemas import ( Token, UserCreate, UserLogin, UserResponse, UserUpdate, ) from shared.auth import ( create_access_token, get_current_user_from_token, get_password_hash, verify_password, ) from shared.config import settings from shared.database import get_db app = FastAPI(title="User Service", version="1.0.0") # CORS middleware app.add_middleware( CORSMiddleware, allow_origins=["*"], # В продакшене ограничить конкретными доменами allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) async def get_current_user( user_data: dict = Depends(get_current_user_from_token), db: AsyncSession = Depends(get_db), ): """Get current user from token via auth dependency.""" # Get full user object from database result = await db.execute(select(User).filter(User.id == user_data["user_id"])) user = result.scalars().first() if user is None: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="User not found" ) return user @app.get("/health") async def health_check(): """Health check endpoint""" return {"status": "healthy", "service": "user_service"} @app.post("/api/v1/register", response_model=UserResponse) async def register_user(user_data: UserCreate, db: AsyncSession = Depends(get_db)): """Register a new user""" # Check if user already exists result = await db.execute(select(User).filter(User.email == user_data.email)) if result.scalars().first(): raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail="Email already registered" ) # Create new user hashed_password = get_password_hash(user_data.password) db_user = User( email=user_data.email, phone=user_data.phone, password_hash=hashed_password, first_name=user_data.first_name, last_name=user_data.last_name, date_of_birth=user_data.date_of_birth, bio=user_data.bio, ) db.add(db_user) await db.commit() await db.refresh(db_user) return UserResponse.model_validate(db_user) @app.post("/api/v1/login", response_model=Token) async def login(user_credentials: UserLogin, db: AsyncSession = Depends(get_db)): """Authenticate user and return token""" result = await db.execute(select(User).filter(User.email == user_credentials.email)) user = result.scalars().first() if not user or not verify_password(user_credentials.password, user.password_hash): raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="Incorrect email or password", ) if not user.is_active: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="Account is deactivated", ) access_token_expires = timedelta(minutes=settings.ACCESS_TOKEN_EXPIRE_MINUTES) access_token = create_access_token( data={"sub": str(user.id), "email": user.email}, expires_delta=access_token_expires, ) return {"access_token": access_token, "token_type": "bearer"} @app.get("/api/v1/profile", response_model=UserResponse) async def get_profile(current_user: User = Depends(get_current_user)): """Get current user profile""" return UserResponse.model_validate(current_user) @app.put("/api/v1/profile", response_model=UserResponse) async def update_profile( user_update: UserUpdate, current_user: User = Depends(get_current_user), db: AsyncSession = Depends(get_db), ): """Update user profile""" update_data = user_update.model_dump(exclude_unset=True) for field, value in update_data.items(): setattr(current_user, field, value) await db.commit() await db.refresh(current_user) return UserResponse.model_validate(current_user) @app.get("/api/v1/health") async def health_check(): """Health check endpoint""" return {"status": "healthy", "service": "user-service"} if __name__ == "__main__": import uvicorn uvicorn.run(app, host="0.0.0.0", port=8001)