# app/schemas/field.py from datetime import datetime from pydantic import BaseModel, Field, validator from typing import Optional, List, Dict, Any from enum import Enum from app.schemas.common import BaseSchema class FieldType(str, Enum): """Типы полей формы""" TEXT = "text" TEXTAREA = "textarea" NUMBER = "number" EMAIL = "email" PHONE = "phone" DATE = "date" DATETIME = "datetime" TIME = "time" SELECT = "select" MULTISELECT = "multiselect" RADIO = "radio" CHECKBOX = "checkbox" FILE = "file" IMAGE = "image" URL = "url" COLOR = "color" RANGE = "range" HIDDEN = "hidden" class FieldValidationRules(BaseModel): """Правила валидации поля""" min_length: Optional[int] = Field(None, ge=0) max_length: Optional[int] = Field(None, ge=0) min_value: Optional[float] = None max_value: Optional[float] = None pattern: Optional[str] = None # regex pattern required: bool = False custom_error_message: Optional[str] = None class FieldOptions(BaseModel): """Опции для полей типа select/radio/checkbox""" options: List[Dict[str, Any]] = Field(default_factory=list) multiple: bool = False searchable: bool = False placeholder: Optional[str] = None class FieldCreate(BaseSchema): """Создание поля""" name: str = Field(..., min_length=1, max_length=100, pattern=r'^[a-zA-Z_][a-zA-Z0-9_]*$') # ✅ заменено regex на pattern label: str = Field(..., min_length=1, max_length=200) field_type: FieldType placeholder: Optional[str] = Field(None, max_length=200) help_text: Optional[str] = None default_value: Optional[Any] = None options: Optional[FieldOptions] = None validation_rules: Optional[FieldValidationRules] = None metadata: Dict[str, Any] = Field(default_factory=dict) order: int = Field(0, ge=0) is_required: bool = False @validator('name') def validate_name(cls, v): if v in ['id', 'created_at', 'updated_at', 'form_id', 'submission_id']: raise ValueError(f'Field name "{v}" is reserved') return v class FieldUpdate(BaseSchema): """Обновление поля""" name: Optional[str] = Field(None, min_length=1, max_length=100, pattern=r'^[a-zA-Z_][a-zA-Z0-9_]*$') # ✅ pattern вместо regex label: Optional[str] = Field(None, min_length=1, max_length=200) field_type: Optional[FieldType] = None placeholder: Optional[str] = None help_text: Optional[str] = None default_value: Optional[Any] = None options: Optional[FieldOptions] = None validation_rules: Optional[FieldValidationRules] = None metadata: Optional[Dict[str, Any]] = None order: Optional[int] = Field(None, ge=0) is_required: Optional[bool] = None class FieldResponse(BaseSchema): id: int name: str label: str field_type: FieldType placeholder: Optional[str] = None help_text: Optional[str] = None options: Dict[str, Any] = Field(default_factory=dict) validation_rules: Dict[str, Any] = Field(default_factory=dict) metadata: Dict[str, Any] = Field(default_factory=dict) created_at: datetime class Config: from_attributes = True