fix(users): выходные схемы пользователя без входных ограничений (/users/me 500 на .local)
UserInDB наследует новую UserReadBase (email/username/full_name без валидации формата). Вход (UserBase/UserCreate/UserUpdate) не менялся. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
2a287480b6
commit
2dc9b4df03
@ -143,7 +143,23 @@ class UserUpdate(BaseModel):
|
||||
load_orgs: bool = Field(default=False)
|
||||
|
||||
|
||||
class UserInDB(UserBase):
|
||||
class UserReadBase(BaseModel):
|
||||
"""Выходная база пользователя без входных ограничений.
|
||||
|
||||
Запись в БД может не проходить входную валидацию (email на .local,
|
||||
короткий username, '<' в full_name), но чтение не должно из-за этого
|
||||
отвечать 500. Входные схемы (UserBase/UserCreate/UserUpdate) не меняются.
|
||||
"""
|
||||
|
||||
email: str
|
||||
username: str
|
||||
full_name: Optional[str] = None
|
||||
role_id: int = 3
|
||||
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
|
||||
class UserInDB(UserReadBase):
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
id: int
|
||||
|
||||
63
api/tests/unit/test_user_schemas.py
Normal file
63
api/tests/unit/test_user_schemas.py
Normal file
@ -0,0 +1,63 @@
|
||||
from datetime import datetime
|
||||
from types import SimpleNamespace
|
||||
|
||||
import pytest
|
||||
from fastapi import FastAPI
|
||||
from fastapi.testclient import TestClient
|
||||
from pydantic import ValidationError
|
||||
|
||||
from src.api.v1.deps import get_current_active_user
|
||||
from src.api.v1.users import router as users_router
|
||||
from src.db.session import get_db
|
||||
from src.domain.schemas import UserAdminListResponse, UserCreate, UserInDB
|
||||
|
||||
_VALID = dict(
|
||||
id=1,
|
||||
email="admin@corp.example",
|
||||
username="admin_1",
|
||||
full_name="Иван Иванов",
|
||||
role_id=1,
|
||||
is_active=True,
|
||||
created_at=datetime(2026, 1, 1),
|
||||
updated_at=None,
|
||||
org_units=[],
|
||||
)
|
||||
|
||||
# Записи, которые API на входе не пропустил бы, но которые могут лежать в БД
|
||||
# (прямой INSERT, например perf-стенд): вывод не должен из-за них падать.
|
||||
_LEGACY = [
|
||||
{"email": "admin@corp.local"},
|
||||
{"username": "rf"},
|
||||
{"full_name": "a<b"},
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.parametrize("override", _LEGACY, ids=["email-local", "short-username", "lt-in-full-name"])
|
||||
def test_output_schemas_accept_legacy_db_rows(override):
|
||||
row = SimpleNamespace(**{**_VALID, **override})
|
||||
assert UserAdminListResponse.model_validate(row).id == 1
|
||||
assert UserInDB.model_validate(row).id == 1
|
||||
|
||||
|
||||
def test_user_create_still_rejects_local_email():
|
||||
with pytest.raises(ValidationError):
|
||||
UserCreate(email="x@corp.local", username="user_1")
|
||||
|
||||
|
||||
def test_users_me_returns_200_for_local_email():
|
||||
app = FastAPI()
|
||||
app.include_router(users_router, prefix="/api/v1")
|
||||
row = SimpleNamespace(**{**_VALID, "email": "admin@corp.local", "username": "rf"})
|
||||
|
||||
async def _user():
|
||||
return row
|
||||
|
||||
async def _db():
|
||||
yield None
|
||||
|
||||
app.dependency_overrides[get_current_active_user] = _user
|
||||
app.dependency_overrides[get_db] = _db
|
||||
|
||||
resp = TestClient(app).get("/api/v1/users/me")
|
||||
assert resp.status_code == 200, resp.text
|
||||
assert resp.json()["email"] == "admin@corp.local"
|
||||
Loading…
x
Reference in New Issue
Block a user