# models/schema/vendor_domain.py """ Pydantic schemas for Vendor Domain operations. Schemas include: - VendorDomainCreate: For adding custom domains - VendorDomainUpdate: For updating domain settings - VendorDomainResponse: Standard domain response - VendorDomainListResponse: Paginated domain list - DomainVerificationInstructions: DNS verification instructions """ import re from datetime import datetime from typing import List, Optional, Dict from pydantic import BaseModel, ConfigDict, Field, field_validator class VendorDomainCreate(BaseModel): """Schema for adding a custom domain to vendor.""" domain: str = Field( ..., description="Custom domain (e.g., myshop.com or shop.mybrand.com)", min_length=3, max_length=255 ) is_primary: bool = Field( default=False, description="Set as primary domain for the vendor" ) @field_validator('domain') @classmethod def validate_domain(cls, v: str) -> str: """Validate and normalize domain.""" # Remove protocol if present domain = v.replace("https://", "").replace("http://", "") # Remove trailing slash domain = domain.rstrip("/") # Convert to lowercase domain = domain.lower().strip() # Basic validation if not domain or '/' in domain: raise ValueError("Invalid domain format") if '.' not in domain: raise ValueError("Domain must have at least one dot") # Check for reserved subdomains reserved = ['www', 'admin', 'api', 'mail', 'smtp', 'ftp', 'cpanel', 'webmail'] first_part = domain.split('.')[0] if first_part in reserved: raise ValueError(f"Domain cannot start with reserved subdomain: {first_part}") # Validate domain format (basic regex) domain_pattern = r'^[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?(\.[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?)*$' if not re.match(domain_pattern, domain): raise ValueError("Invalid domain format") return domain class VendorDomainUpdate(BaseModel): """Schema for updating vendor domain settings.""" is_primary: Optional[bool] = Field(None, description="Set as primary domain") is_active: Optional[bool] = Field(None, description="Activate or deactivate domain") model_config = ConfigDict(from_attributes=True) class VendorDomainResponse(BaseModel): """Standard schema for vendor domain response.""" model_config = ConfigDict(from_attributes=True) id: int vendor_id: int domain: str is_primary: bool is_active: bool is_verified: bool ssl_status: str verification_token: Optional[str] = None verified_at: Optional[datetime] = None ssl_verified_at: Optional[datetime] = None created_at: datetime updated_at: datetime class VendorDomainListResponse(BaseModel): """Schema for paginated vendor domain list.""" domains: List[VendorDomainResponse] total: int class DomainVerificationInstructions(BaseModel): """DNS verification instructions for domain ownership.""" domain: str verification_token: str instructions: Dict[str, str] txt_record: Dict[str, str] common_registrars: Dict[str, str] model_config = ConfigDict(from_attributes=True) class DomainVerificationResponse(BaseModel): """Response after domain verification.""" message: str domain: str verified_at: datetime is_verified: bool class DomainDeletionResponse(BaseModel): """Response after domain deletion.""" message: str domain: str vendor_id: int