from datetime import datetime from typing import Literal from pydantic import BaseModel, ConfigDict, Field, HttpUrl, field_validator DocumentType = Literal[ "manual", "service_manual", "schematic", "alignment", "parts_list", "firmware", "datasheet", "service_bulletin", "other", ] NoteType = Literal["repair", "known_fault", "alignment", "spare_part", "general"] NoteSeverity = Literal["low", "medium", "high", "critical", ""] def normalize_text(value: object) -> str: if value is None: return "" return str(value).strip() def normalize_tags(value: object) -> list[str]: if value is None or value == "": return [] if isinstance(value, str): parts = value.split(",") elif isinstance(value, list): parts = value else: parts = [] seen: set[str] = set() tags: list[str] = [] for part in parts: tag = str(part).strip() key = tag.lower() if tag and key not in seen: seen.add(key) tags.append(tag) return tags class KnowledgeManufacturerBase(BaseModel): name: str = Field(min_length=2, max_length=160) website: HttpUrl | None = None notes: str = "" @field_validator("name", "notes", mode="before") @classmethod def normalize_text_fields(cls, value: object) -> str: return normalize_text(value) class KnowledgeManufacturerCreate(KnowledgeManufacturerBase): pass class KnowledgeManufacturerUpdate(KnowledgeManufacturerBase): pass class KnowledgeManufacturerResponse(KnowledgeManufacturerBase): id: int slug: str website: str created_at: datetime updated_at: datetime model_config = ConfigDict(from_attributes=True) class KnowledgeDeviceBase(BaseModel): manufacturer_id: int name: str = Field(min_length=2, max_length=180) model_number: str = Field(default="", max_length=120) device_type: str = Field(default="", max_length=80) frequency_range: str = Field(default="", max_length=120) production_year_from: int | None = Field(default=None, ge=1900, le=2100) production_year_to: int | None = Field(default=None, ge=1900, le=2100) notes: str = "" @field_validator("name", "model_number", "device_type", "frequency_range", "notes", mode="before") @classmethod def normalize_text_fields(cls, value: object) -> str: return normalize_text(value) class KnowledgeDeviceCreate(KnowledgeDeviceBase): pass class KnowledgeDeviceUpdate(KnowledgeDeviceBase): pass class KnowledgeDeviceResponse(KnowledgeDeviceBase): id: int slug: str created_at: datetime updated_at: datetime manufacturer: KnowledgeManufacturerResponse model_config = ConfigDict(from_attributes=True) class KnowledgeDocumentBase(BaseModel): manufacturer_id: int device_id: int | None = None title: str = Field(min_length=2, max_length=255) document_type: DocumentType language: str = Field(default="de", min_length=2, max_length=20) external_url: HttpUrl | None = None paperless_document_id: str = Field(default="", max_length=120) description: str = "" tags: list[str] = Field(default_factory=list) @field_validator("title", "language", "paperless_document_id", "description", mode="before") @classmethod def normalize_text_fields(cls, value: object) -> str: return normalize_text(value) @field_validator("tags", mode="before") @classmethod def normalize_tag_fields(cls, value: object) -> list[str]: return normalize_tags(value) class KnowledgeDocumentCreate(KnowledgeDocumentBase): pass class KnowledgeDocumentUpdate(KnowledgeDocumentBase): pass class KnowledgeDocumentResponse(KnowledgeDocumentBase): id: int slug: str external_url: str file_name: str file_path: str mime_type: str file_size: int checksum_sha256: str created_at: datetime updated_at: datetime manufacturer: KnowledgeManufacturerResponse device: KnowledgeDeviceResponse | None = None model_config = ConfigDict(from_attributes=True) class KnowledgeNoteBase(BaseModel): manufacturer_id: int | None = None device_id: int | None = None title: str = Field(min_length=2, max_length=255) content: str = Field(min_length=1) note_type: NoteType = "general" severity: NoteSeverity = "" tags: list[str] = Field(default_factory=list) @field_validator("title", "content", "severity", mode="before") @classmethod def normalize_text_fields(cls, value: object) -> str: return normalize_text(value) @field_validator("tags", mode="before") @classmethod def normalize_tag_fields(cls, value: object) -> list[str]: return normalize_tags(value) class KnowledgeNoteCreate(KnowledgeNoteBase): pass class KnowledgeNoteUpdate(KnowledgeNoteBase): pass class KnowledgeNoteResponse(KnowledgeNoteBase): id: int created_at: datetime updated_at: datetime manufacturer: KnowledgeManufacturerResponse | None = None device: KnowledgeDeviceResponse | None = None model_config = ConfigDict(from_attributes=True) class KnowledgeSearchResult(BaseModel): entity_type: str id: int title: str subtitle: str = "" href: str