from fastapi import FastAPI, HTTPException, Depends, status from fastapi.middleware.cors import CORSMiddleware from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy import select from datetime import timedelta from shared.config import settings from shared.database import get_db from shared.auth import ( verify_password, get_password_hash, create_access_token, get_current_user_from_token ) from services.user_service.models import User from services.user_service.schemas import UserCreate, UserResponse, UserLogin, Token, UserUpdate 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)