"""Publishing / SEO / PWA DTOs — Phase 11.7.""" from __future__ import annotations from datetime import datetime from uuid import UUID from pydantic import BaseModel, ConfigDict, Field from app.models.types import ( DomainEdgeStatus, PublishReleaseStatus, PublishTarget, PwaStatus, RobotsStatus, SeoStatus, SeoTarget, SitemapStatus, ) from app.schemas.common import ORMBase _FORBID = ConfigDict(extra="forbid") class PublishReleaseCreate(BaseModel): model_config = _FORBID workspace_id: UUID target_type: PublishTarget target_id: UUID notes: str | None = None metadata_json: dict | None = None class PublishReleaseUpdate(BaseModel): model_config = _FORBID status: PublishReleaseStatus | None = None notes: str | None = None error_message: str | None = None metadata_json: dict | None = None version: int = Field(ge=1) class PublishReleaseRead(ORMBase): id: UUID tenant_id: UUID workspace_id: UUID target_type: PublishTarget target_id: UUID status: PublishReleaseStatus notes: str | None error_message: str | None completed_at: datetime | None metadata_json: dict | None version: int is_deleted: bool created_by: str | None updated_by: str | None created_at: datetime updated_at: datetime class PublishReleaseListResponse(BaseModel): items: list[PublishReleaseRead] total: int page: int page_size: int class DomainEdgeBindingCreate(BaseModel): model_config = _FORBID workspace_id: UUID site_id: UUID site_domain_id: UUID dns_status_ref: str | None = Field(default=None, max_length=255) ssl_cert_ref: str | None = Field(default=None, max_length=255) edge_map_ref: str | None = Field(default=None, max_length=255) status: DomainEdgeStatus = DomainEdgeStatus.PENDING metadata_json: dict | None = None class DomainEdgeBindingUpdate(BaseModel): model_config = _FORBID status: DomainEdgeStatus | None = None dns_status_ref: str | None = Field(default=None, max_length=255) ssl_cert_ref: str | None = Field(default=None, max_length=255) edge_map_ref: str | None = Field(default=None, max_length=255) metadata_json: dict | None = None version: int = Field(ge=1) class DomainEdgeBindingRead(ORMBase): id: UUID tenant_id: UUID workspace_id: UUID site_id: UUID site_domain_id: UUID host: str status: DomainEdgeStatus dns_status_ref: str | None ssl_cert_ref: str | None edge_map_ref: str | None metadata_json: dict | None version: int is_deleted: bool created_by: str | None updated_by: str | None created_at: datetime updated_at: datetime class DomainEdgeBindingListResponse(BaseModel): items: list[DomainEdgeBindingRead] total: int page: int page_size: int class SeoMetadataUpsert(BaseModel): model_config = _FORBID workspace_id: UUID target_type: SeoTarget target_id: UUID status: SeoStatus = SeoStatus.DRAFT title: str | None = Field(default=None, max_length=255) description: str | None = None canonical_url: str | None = Field(default=None, max_length=500) robots_directive: str | None = Field(default=None, max_length=100) og_json: dict | None = None metadata_json: dict | None = None version: int | None = Field(default=None, ge=1) class SeoMetadataUpdate(BaseModel): model_config = _FORBID status: SeoStatus | None = None title: str | None = Field(default=None, max_length=255) description: str | None = None canonical_url: str | None = Field(default=None, max_length=500) robots_directive: str | None = Field(default=None, max_length=100) og_json: dict | None = None metadata_json: dict | None = None version: int = Field(ge=1) class SeoMetadataRead(ORMBase): id: UUID tenant_id: UUID workspace_id: UUID target_type: SeoTarget target_id: UUID status: SeoStatus title: str | None description: str | None canonical_url: str | None robots_directive: str | None og_json: dict | None metadata_json: dict | None version: int is_deleted: bool created_by: str | None updated_by: str | None created_at: datetime updated_at: datetime class SeoMetadataListResponse(BaseModel): items: list[SeoMetadataRead] total: int page: int page_size: int class SitemapShellUpsert(BaseModel): model_config = _FORBID workspace_id: UUID site_id: UUID status: SitemapStatus = SitemapStatus.DRAFT entries_json: dict | None = None storage_file_ref: str | None = Field(default=None, max_length=255) metadata_json: dict | None = None version: int | None = Field(default=None, ge=1) class SitemapShellUpdate(BaseModel): model_config = _FORBID status: SitemapStatus | None = None entries_json: dict | None = None storage_file_ref: str | None = Field(default=None, max_length=255) metadata_json: dict | None = None version: int = Field(ge=1) class SitemapShellRead(ORMBase): id: UUID tenant_id: UUID workspace_id: UUID site_id: UUID status: SitemapStatus entries_json: dict | None storage_file_ref: str | None metadata_json: dict | None version: int is_deleted: bool created_by: str | None updated_by: str | None created_at: datetime updated_at: datetime class SitemapShellListResponse(BaseModel): items: list[SitemapShellRead] total: int page: int page_size: int class RobotsShellUpsert(BaseModel): model_config = _FORBID workspace_id: UUID site_id: UUID status: RobotsStatus = RobotsStatus.DRAFT content_text: str | None = None rules_json: dict | None = None metadata_json: dict | None = None version: int | None = Field(default=None, ge=1) class RobotsShellUpdate(BaseModel): model_config = _FORBID status: RobotsStatus | None = None content_text: str | None = None rules_json: dict | None = None metadata_json: dict | None = None version: int = Field(ge=1) class RobotsShellRead(ORMBase): id: UUID tenant_id: UUID workspace_id: UUID site_id: UUID status: RobotsStatus content_text: str | None rules_json: dict | None metadata_json: dict | None version: int is_deleted: bool created_by: str | None updated_by: str | None created_at: datetime updated_at: datetime class RobotsShellListResponse(BaseModel): items: list[RobotsShellRead] total: int page: int page_size: int class PwaManifestUpsert(BaseModel): model_config = _FORBID workspace_id: UUID site_id: UUID status: PwaStatus = PwaStatus.DRAFT name: str | None = Field(default=None, max_length=255) short_name: str | None = Field(default=None, max_length=100) start_url: str | None = Field(default=None, max_length=500) manifest_json: dict | None = None service_worker_ref: str | None = Field(default=None, max_length=255) metadata_json: dict | None = None version: int | None = Field(default=None, ge=1) class PwaManifestUpdate(BaseModel): model_config = _FORBID status: PwaStatus | None = None name: str | None = Field(default=None, max_length=255) short_name: str | None = Field(default=None, max_length=100) start_url: str | None = Field(default=None, max_length=500) manifest_json: dict | None = None service_worker_ref: str | None = Field(default=None, max_length=255) metadata_json: dict | None = None version: int = Field(ge=1) class PwaManifestRead(ORMBase): id: UUID tenant_id: UUID workspace_id: UUID site_id: UUID status: PwaStatus name: str | None short_name: str | None start_url: str | None manifest_json: dict | None service_worker_ref: str | None metadata_json: dict | None version: int is_deleted: bool created_by: str | None updated_by: str | None created_at: datetime updated_at: datetime class PwaManifestListResponse(BaseModel): items: list[PwaManifestRead] total: int page: int page_size: int