"""Request/response schemas for the section-field library (字段管理).""" from datetime import datetime from decimal import Decimal from pydantic import BaseModel, ConfigDict, Field from app.schemas.common import TypographyMixin class SectionFieldBase(TypographyMixin, BaseModel): """Fields a client may set on a section field.""" #: Display name, numbering included — e.g. ``"1. Introduction"``. Stored #: and rendered verbatim; the API never rewrites it. name: str = Field(min_length=1, max_length=255) #: Heading depth. 1 = "1.", 2 = "1.1", 3 = "1.1.1". Rendering hint only. level: int = Field(default=1, ge=1, le=9) #: Font size in points. Fractional because 五号 = 10.5pt. font_size: Decimal = Field(default=Decimal("12.0"), gt=0, le=99) #: ``#RRGGBB``. ``rgb(...)`` and shorthand forms are normalised on write. font_color: str = Field(default="#000000", max_length=32) class SectionFieldCreate(SectionFieldBase): """Payload for ``POST /section-fields``.""" class SectionFieldUpdate(TypographyMixin, BaseModel): """Payload for ``PATCH /section-fields/{id}`` — every part optional. The colour normaliser tolerates ``None`` here; the validator returns non-strings untouched, so an omitted colour stays omitted. """ name: str | None = Field(default=None, min_length=1, max_length=255) level: int | None = Field(default=None, ge=1, le=9) font_size: Decimal | None = Field(default=None, gt=0, le=99) font_color: str | None = Field(default=None, max_length=32) class SectionFieldRead(SectionFieldBase): """A stored section field.""" model_config = ConfigDict(from_attributes=True) id: int created_at: datetime updated_at: datetime class SectionFieldRef(BaseModel): """How many templates currently place a field — used to explain a refusal.""" field_id: int field_name: str template_count: int