from fastapi import Depends, FastAPI, HTTPException, status from fastapi.middleware.cors import CORSMiddleware from sqlalchemy.orm import Session from .auth import create_access_token from .core.config import settings from .crud import authenticate_user, create_address, create_user, get_user_by_email from .db.session import Base, engine, get_db from .dependencies import get_current_user from .models import Address, User from .schemas import AddressCreate, AddressRead, TokenResponse, UserCreate, UserLogin, UserRead app = FastAPI(title='Flutter Auth API', version='1.0.0') app.add_middleware( CORSMiddleware, allow_origins=settings.cors_origin_list, allow_credentials=True, allow_methods=['*'], allow_headers=['*'], ) @app.on_event('startup') def on_startup() -> None: Base.metadata.create_all(bind=engine) @app.get('/health') def health_check() -> dict[str, str]: return {'status': 'ok'} @app.post('/auth/register', response_model=TokenResponse, status_code=status.HTTP_201_CREATED) def register(payload: UserCreate, db: Session = Depends(get_db)) -> TokenResponse: existing_user = get_user_by_email(db, payload.email) if existing_user is not None: raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail='Ya existe un usuario con ese correo') user = create_user(db, payload) token = create_access_token(user_id=user.id, email=user.email) return TokenResponse(token=token, user=UserRead.model_validate(user)) @app.post('/auth/login', response_model=TokenResponse) def login(payload: UserLogin, db: Session = Depends(get_db)) -> TokenResponse: user = authenticate_user(db, payload.email, payload.password) if user is None: raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail='Correo o contraseña inválidos') token = create_access_token(user_id=user.id, email=user.email) return TokenResponse(token=token, user=UserRead.model_validate(user)) @app.get('/me', response_model=UserRead) def read_me(current_user: User = Depends(get_current_user)) -> UserRead: return UserRead.model_validate(current_user) @app.post('/addresses', response_model=AddressRead, status_code=status.HTTP_201_CREATED) def save_address( payload: AddressCreate, db: Session = Depends(get_db), current_user: User = Depends(get_current_user), ) -> AddressRead: if payload.email is not None and payload.email != current_user.email: raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail='El correo no coincide con el usuario autenticado') address = create_address(db, current_user, payload) return AddressRead.model_validate(address) @app.get('/addresses/me', response_model=list[AddressRead]) def read_my_addresses( db: Session = Depends(get_db), current_user: User = Depends(get_current_user), ) -> list[AddressRead]: addresses = sorted(current_user.addresses, key=lambda address: address.created_at, reverse=True) return [AddressRead.model_validate(address) for address in addresses]