refactor(schemas): одна модель филиала в schemas/directories.py (R-13)
RegionalOfficeOut больше не дублируется в schemas/me.py: в schemas/directories.py определены RegionalOfficeBrief (id, name, is_head_office — форма /me Среза 0) и RegionalOfficeOut(RegionalOfficeBrief) с is_active. /me импортирует RegionalOfficeBrief, тело ответа /me не меняется; в OpenAPI нет двух одноимённых компонентов. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012vJkmBGKKqMoEMzvsXG3y2
This commit is contained in:
parent
83746e694e
commit
4dd966b0b7
@ -9,7 +9,8 @@ from typing import Annotated
|
||||
from fastapi import APIRouter, Depends
|
||||
|
||||
from src.api.dependencies.auth import Principal, current_user
|
||||
from src.schemas.me import MeResponse, RegionalOfficeOut
|
||||
from src.schemas.directories import RegionalOfficeBrief
|
||||
from src.schemas.me import MeResponse
|
||||
|
||||
router = APIRouter(tags=["me"])
|
||||
|
||||
@ -24,7 +25,7 @@ async def get_me(principal: Annotated[Principal, Depends(current_user)]) -> MeRe
|
||||
# пользователь найден по email, поэтому он заполнен; пустая строка — лишь для типов (колонка nullable)
|
||||
email=user.email or "",
|
||||
full_name=user.full_name,
|
||||
regional_office=RegionalOfficeOut(id=office.id, name=office.name, is_head_office=office.is_head_office),
|
||||
regional_office=RegionalOfficeBrief.model_validate(office),
|
||||
business_segment=user.business_segment,
|
||||
roles=sorted(principal.roles),
|
||||
permissions=sorted(principal.permissions),
|
||||
|
||||
@ -19,14 +19,19 @@ def _blank_to_none(value: str | None) -> str | None:
|
||||
return stripped or None
|
||||
|
||||
|
||||
class RegionalOfficeOut(BaseModel):
|
||||
"""Филиал (`GET /directories/regional-offices`)."""
|
||||
class RegionalOfficeBrief(BaseModel):
|
||||
"""Филиал кратко: профиль `GET /me` (форма ответа Среза 0 — без `is_active`)."""
|
||||
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
id: uuid.UUID
|
||||
name: str
|
||||
is_head_office: bool
|
||||
|
||||
|
||||
class RegionalOfficeOut(RegionalOfficeBrief):
|
||||
"""Филиал целиком (`GET /directories/regional-offices`, пользователи администратора)."""
|
||||
|
||||
is_active: bool
|
||||
|
||||
|
||||
|
||||
@ -5,14 +5,7 @@ import uuid
|
||||
from pydantic import BaseModel, ConfigDict
|
||||
|
||||
from src.models.enums import BusinessSegment
|
||||
|
||||
|
||||
class RegionalOfficeOut(BaseModel):
|
||||
"""Филиал пользователя."""
|
||||
|
||||
id: uuid.UUID
|
||||
name: str
|
||||
is_head_office: bool
|
||||
from src.schemas.directories import RegionalOfficeBrief
|
||||
|
||||
|
||||
class MeResponse(BaseModel):
|
||||
@ -23,7 +16,7 @@ class MeResponse(BaseModel):
|
||||
id: uuid.UUID
|
||||
email: str
|
||||
full_name: str
|
||||
regional_office: RegionalOfficeOut
|
||||
regional_office: RegionalOfficeBrief
|
||||
business_segment: BusinessSegment | None
|
||||
roles: list[str]
|
||||
permissions: list[str]
|
||||
|
||||
@ -34,7 +34,8 @@ from src.models.access import AppUser, Role, UserRole
|
||||
from src.models.directories import RegionalOffice
|
||||
from src.models.enums import BusinessSegment
|
||||
from src.repositories.users import AmbiguousUserError, load_principal_data
|
||||
from src.schemas.me import MeResponse, RegionalOfficeOut
|
||||
from src.schemas.directories import RegionalOfficeBrief
|
||||
from src.schemas.me import MeResponse
|
||||
|
||||
SECRET = "test-secret-for-auth-deps-0123456789abcdef"
|
||||
OTHER_SECRET = "foreign-secret-for-auth-deps-0123456789ab"
|
||||
@ -487,7 +488,7 @@ async def test_repository_raises_on_ambiguity(seeded: AsyncSession) -> None:
|
||||
|
||||
|
||||
def test_me_response_schema_serializes_enum_and_null_segment() -> None:
|
||||
office = RegionalOfficeOut(id=uuid.uuid4(), name="ГО", is_head_office=True)
|
||||
office = RegionalOfficeBrief(id=uuid.uuid4(), name="ГО", is_head_office=True)
|
||||
fields: dict[str, Any] = {
|
||||
"id": uuid.uuid4(),
|
||||
"email": "a@b.c",
|
||||
|
||||
@ -36,7 +36,7 @@ from src.db.db import get_async_session
|
||||
from src.models.directories import RegionalOffice
|
||||
from src.models.enums import AuditAction, AuditSection
|
||||
from src.schemas.common import ErrorDetail, Page, PageParams
|
||||
from src.schemas.me import RegionalOfficeOut
|
||||
from src.schemas.directories import RegionalOfficeBrief
|
||||
from src.services.audit import AuditService
|
||||
from tests.pg_helpers import alembic_async
|
||||
|
||||
@ -141,8 +141,8 @@ def test_domain_error_extra_cannot_shadow_code_or_message() -> None:
|
||||
|
||||
|
||||
def test_page_serializes() -> None:
|
||||
office = RegionalOfficeOut(id=CONFLICT_ID, name="ГО", is_head_office=True)
|
||||
page = Page[RegionalOfficeOut](items=[office], total=7, limit=1, offset=3)
|
||||
office = RegionalOfficeBrief(id=CONFLICT_ID, name="ГО", is_head_office=True)
|
||||
page = Page[RegionalOfficeBrief](items=[office], total=7, limit=1, offset=3)
|
||||
assert page.model_dump(mode="json") == {
|
||||
"items": [{"id": str(CONFLICT_ID), "name": "ГО", "is_head_office": True}],
|
||||
"total": 7,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user