# app/modules/cms/schemas/content_page.py """ Content Page Pydantic schemas for API request/response validation. Schemas are organized by context: - Admin: Full CRUD with platform-level access - Store: Store-scoped CRUD with usage limits - Public/Shop: Read-only public access """ from pydantic import BaseModel, ConfigDict, Field # ============================================================================ # ADMIN SCHEMAS # ============================================================================ class ContentPageCreate(BaseModel): """Schema for creating a content page (admin).""" slug: str = Field( ..., max_length=100, description="URL-safe identifier (about, faq, contact, etc.)", ) title: str = Field(..., max_length=200, description="Page title") title_translations: dict[str, str] | None = Field( None, description="Title translations keyed by language code" ) content: str = Field(..., description="HTML or Markdown content") content_translations: dict[str, str] | None = Field( None, description="Content translations keyed by language code" ) content_format: str = Field( default="html", description="Content format: html or markdown" ) template: str = Field( default="default", max_length=50, description="Template name (default, minimal, modern, full)", ) meta_description: str | None = Field( None, max_length=300, description="SEO meta description" ) meta_description_translations: dict[str, str] | None = Field( None, description="Meta description translations keyed by language code" ) is_published: bool = Field(default=False, description="Publish immediately") show_in_footer: bool = Field(default=True, description="Show in footer navigation") show_in_header: bool = Field(default=False, description="Show in header navigation") show_in_legal: bool = Field( default=False, description="Show in legal/bottom bar (next to copyright)" ) display_order: int = Field(default=0, description="Display order (lower = first)") store_id: int | None = Field( None, description="Store ID (None for platform default)" ) class ContentPageUpdate(BaseModel): """Schema for updating a content page (admin).""" title: str | None = Field(None, max_length=200) title_translations: dict[str, str] | None = None content: str | None = None content_translations: dict[str, str] | None = None content_format: str | None = None template: str | None = Field(None, max_length=50) meta_description: str | None = Field(None, max_length=300) meta_description_translations: dict[str, str] | None = None is_published: bool | None = None show_in_footer: bool | None = None show_in_header: bool | None = None show_in_legal: bool | None = None display_order: int | None = None class ContentPageResponse(BaseModel): """Schema for content page response (admin/store).""" model_config = ConfigDict(from_attributes=True) id: int platform_id: int | None = None platform_code: str | None = None platform_name: str | None = None store_id: int | None store_name: str | None slug: str title: str title_translations: dict[str, str] | None = None content: str content_translations: dict[str, str] | None = None content_format: str template: str | None = None meta_description: str | None meta_description_translations: dict[str, str] | None = None is_published: bool published_at: str | None display_order: int show_in_footer: bool show_in_header: bool show_in_legal: bool is_platform_page: bool = False is_store_default: bool = False is_store_override: bool = False page_tier: str | None = None created_at: str updated_at: str created_by: int | None updated_by: int | None class HomepageSectionsResponse(BaseModel): """Response containing homepage sections with platform language info.""" sections: dict | None = None supported_languages: list[str] = Field(default_factory=lambda: ["fr", "de", "en"]) default_language: str = "fr" class SectionUpdateResponse(BaseModel): """Response after updating sections.""" message: str sections: dict | None = None # ============================================================================ # STORE SCHEMAS # ============================================================================ class StoreContentPageCreate(BaseModel): """Schema for creating a store content page.""" slug: str = Field( ..., max_length=100, description="URL-safe identifier (about, faq, contact, etc.)", ) title: str = Field(..., max_length=200, description="Page title") content: str = Field(..., description="HTML or Markdown content") content_format: str = Field( default="html", description="Content format: html or markdown" ) meta_description: str | None = Field( None, max_length=300, description="SEO meta description" ) is_published: bool = Field(default=False, description="Publish immediately") show_in_footer: bool = Field(default=True, description="Show in footer navigation") show_in_header: bool = Field(default=False, description="Show in header navigation") show_in_legal: bool = Field( default=False, description="Show in legal/bottom bar (next to copyright)" ) display_order: int = Field(default=0, description="Display order (lower = first)") class StoreContentPageUpdate(BaseModel): """Schema for updating a store content page.""" title: str | None = Field(None, max_length=200) content: str | None = None content_format: str | None = None meta_description: str | None = Field(None, max_length=300) is_published: bool | None = None show_in_footer: bool | None = None show_in_header: bool | None = None show_in_legal: bool | None = None display_order: int | None = None class CMSUsageResponse(BaseModel): """Schema for CMS usage statistics.""" total_pages: int custom_pages: int override_pages: int pages_limit: int | None custom_pages_limit: int | None can_create_page: bool can_create_custom: bool usage_percent: float custom_usage_percent: float # ============================================================================ # PUBLIC/SHOP SCHEMAS # ============================================================================ class PublicContentPageResponse(BaseModel): """Public content page response (no internal IDs).""" slug: str title: str content: str content_format: str meta_description: str | None published_at: str | None class ContentPageListItem(BaseModel): """Content page list item for navigation.""" slug: str title: str show_in_footer: bool show_in_header: bool display_order: int