|
1 | | -from datetime import timedelta |
| 1 | +from datetime import timedelta, datetime |
2 | 2 | from typing import Annotated |
3 | 3 | from fastapi import APIRouter, Depends, HTTPException, status, Request |
4 | 4 | from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm |
|
7 | 7 | from sqlalchemy.exc import IntegrityError |
8 | 8 | from database import get_db |
9 | 9 | from models_db import User |
| 10 | +from core.schemas import UserCreate, UserResponse |
10 | 11 | from core.security import verify_password, create_access_token, get_password_hash, ACCESS_TOKEN_EXPIRE_MINUTES, SECRET_KEY, ALGORITHM |
11 | 12 |
|
12 | 13 | router = APIRouter(prefix="/auth", tags=["Auth"]) |
@@ -84,42 +85,64 @@ async def login_for_access_token( |
84 | 85 | } |
85 | 86 | } |
86 | 87 |
|
87 | | -@router.post("/register") |
| 88 | +@router.post("/register", response_model=UserResponse, status_code=status.HTTP_201_CREATED) |
88 | 89 | async def register_user( |
89 | | - email: str, |
90 | | - password: str, |
91 | | - name: str = "Trader", |
| 90 | + user_data: UserCreate, |
92 | 91 | db: Session = Depends(get_db) |
93 | 92 | ): |
94 | | - """(Dev Helper) Registra un usuario inicial.""" |
95 | | - # Verificar si existe |
96 | | - result = db.execute(select(User).where(User.email == email)) |
| 93 | + """ |
| 94 | + Registra un nuevo usuario en la plataforma. |
| 95 | + |
| 96 | + - Valida email único (409 Conflict) |
| 97 | + - Hashing seguro de contraseña (bcrypt) |
| 98 | + - Retorna el usuario creado (DTO seguro sin password) |
| 99 | + """ |
| 100 | + # 1. Normalizar email |
| 101 | + email_norm = user_data.email.strip().lower() |
| 102 | + |
| 103 | + # 2. Verificar duplicado |
| 104 | + result = db.execute(select(User).where(User.email == email_norm)) |
97 | 105 | existing_user = result.scalars().first() |
98 | 106 |
|
99 | 107 | if existing_user: |
100 | | - raise HTTPException(status_code=400, detail="Email already registered") |
| 108 | + raise HTTPException( |
| 109 | + status_code=status.HTTP_409_CONFLICT, |
| 110 | + detail="Email already registered" |
| 111 | + ) |
101 | 112 |
|
102 | | - hashed_pwd = get_password_hash(password) |
103 | | - new_user = User(email=email, hashed_password=hashed_pwd, name=name, role="user") |
| 113 | + # 3. Hash Password |
| 114 | + hashed_pwd = get_password_hash(user_data.password) |
| 115 | + |
| 116 | + # 4. Crear Usuario |
| 117 | + new_user = User( |
| 118 | + email=email_norm, |
| 119 | + hashed_password=hashed_pwd, |
| 120 | + name=user_data.name, |
| 121 | + role="user", |
| 122 | + plan="free", |
| 123 | + plan_status="active", |
| 124 | + created_at=datetime.utcnow() # Ensure model has this or defaults |
| 125 | + ) |
104 | 126 |
|
105 | | - db.add(new_user) |
106 | 127 | try: |
| 128 | + db.add(new_user) |
107 | 129 | db.commit() |
108 | 130 | db.refresh(new_user) |
109 | | - return {"id": new_user.id, "email": new_user.email, "msg": "User created"} |
| 131 | + return new_user |
| 132 | + |
110 | 133 | except IntegrityError: |
111 | 134 | db.rollback() |
112 | | - raise HTTPException(status_code=400, detail="Error creating user") |
113 | | - |
114 | | - return { |
115 | | - "id": current_user.id, |
116 | | - "email": current_user.email, |
117 | | - "name": current_user.name, |
118 | | - "role": current_user.role, |
119 | | - "plan": current_user.plan, |
120 | | - "plan_status": current_user.plan_status, |
121 | | - "avatar_url": f"https://ui-avatars.com/api/?name={current_user.name}&background=10b981&color=fff" |
122 | | - } |
| 135 | + raise HTTPException( |
| 136 | + status_code=status.HTTP_400_BAD_REQUEST, |
| 137 | + detail="Error creating user (Integrity)" |
| 138 | + ) |
| 139 | + except Exception as e: |
| 140 | + db.rollback() |
| 141 | + print(f"[AUTH ERROR] Register failed: {e}") |
| 142 | + raise HTTPException( |
| 143 | + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, |
| 144 | + detail="Internal server error during registration" |
| 145 | + ) |
123 | 146 |
|
124 | 147 | # Entitlements Endpoint (Sync DB required for core logic) |
125 | 148 | from database import SessionLocal |
|
0 commit comments