Files
chat/services/user_service/main.py
2025-09-25 08:05:25 +09:00

140 lines
4.4 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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)