api schema check
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
2025-09-26 07:28:07 +09:00
parent e5aa933cf9
commit ed8eb75bac
96 changed files with 24213 additions and 13 deletions

View File

@@ -134,36 +134,65 @@ async def register_user(user_data: UserCreate, db: AsyncSession = Depends(get_db
@app.post("/api/v1/auth/login", response_model=Token)
async def login(user_credentials: UserLogin, db: AsyncSession = Depends(get_db)):
"""Authenticate user and return token"""
print(f"Login attempt: email={user_credentials.email}, username={user_credentials.username}")
# Проверка валидности входных данных
if not user_credentials.email and not user_credentials.username:
print("Error: Neither email nor username provided")
raise HTTPException(
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
detail="Either email or username must be provided",
)
if not user_credentials.password:
print("Error: Password not provided")
raise HTTPException(
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
detail="Password is required",
)
# Определяем, по какому полю ищем пользователя
user = None
if user_credentials.email:
result = await db.execute(select(User).filter(User.email == user_credentials.email))
user = result.scalars().first()
elif user_credentials.username:
result = await db.execute(select(User).filter(User.username == user_credentials.username))
user = result.scalars().first()
else:
try:
if user_credentials.email:
print(f"Looking up user by email: {user_credentials.email}")
result = await db.execute(select(User).filter(User.email == user_credentials.email))
user = result.scalars().first()
elif user_credentials.username:
print(f"Looking up user by username: {user_credentials.username}")
result = await db.execute(select(User).filter(User.username == user_credentials.username))
user = result.scalars().first()
except Exception as e:
print(f"Database error during user lookup: {str(e)}")
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail="Either email or username must be provided",
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="Database error during authentication",
)
# Проверяем наличие пользователя и правильность пароля
if not user:
print(f"User not found: email={user_credentials.email}, username={user_credentials.username}")
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Incorrect email or password",
)
print(f"User found: id={user.id}, email={user.email}")
# Проверка пароля
try:
if not verify_password(user_credentials.password, str(user.password_hash)):
password_valid = verify_password(user_credentials.password, str(user.password_hash))
print(f"Password verification result: {password_valid}")
if not password_valid:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Incorrect email or password",
)
except Exception:
except HTTPException:
raise
except Exception as e:
# Если произошла ошибка при проверке пароля, то считаем, что пароль неверный
print(f"Password verification error: {str(e)}")
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Incorrect email or password",
@@ -172,21 +201,25 @@ async def login(user_credentials: UserLogin, db: AsyncSession = Depends(get_db))
# Проверка активности аккаунта
try:
is_active = bool(user.is_active)
print(f"User active status: {is_active}")
if not is_active:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Account is inactive",
)
except Exception:
except Exception as e:
# Если произошла ошибка при проверке активности, считаем аккаунт активным
print(f"Error checking user active status: {str(e)}")
pass
print("Creating access token...")
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,
)
print("Login successful")
return {"access_token": access_token, "token_type": "bearer"}

View File

@@ -108,10 +108,21 @@ class UserLogin(BaseModel):
@classmethod
def validate_password_bytes(cls, v):
"""Ensure password doesn't exceed bcrypt's 72-byte limit."""
if not v or len(v.strip()) == 0:
raise ValueError("Password cannot be empty")
password_bytes = v.encode('utf-8')
if len(password_bytes) > 72:
raise ValueError("Password is too long when encoded as UTF-8 (max 72 bytes for bcrypt)")
return v
@field_validator("username")
@classmethod
def validate_login_fields(cls, v, info):
"""Ensure at least email or username is provided."""
email = info.data.get('email')
if not email and not v:
raise ValueError("Either email or username must be provided")
return v
class Token(BaseModel):