""" Pydantic Schemas für Content Service API """ from pydantic import BaseModel, Field, validator from typing import Optional, List from datetime import datetime from models import ContentType, CCLicense, ContentCategory, ContentStatus # ============= REQUEST SCHEMAS ============= class ContentCreate(BaseModel): """Schema für Content Creation""" title: str = Field(..., min_length=3, max_length=500) description: Optional[str] = Field(None, max_length=5000) content_type: ContentType category: ContentCategory license: CCLicense = CCLicense.CC_BY_SA age_min: int = Field(6, ge=3, le=18) age_max: int = Field(18, ge=3, le=18) embed_url: Optional[str] = None tags: List[str] = [] @validator('age_max') def age_max_must_be_greater(cls, v, values): if 'age_min' in values and v < values['age_min']: raise ValueError('age_max must be >= age_min') return v class ContentUpdate(BaseModel): """Schema für Content Update""" title: Optional[str] = Field(None, min_length=3, max_length=500) description: Optional[str] = Field(None, max_length=5000) category: Optional[ContentCategory] = None license: Optional[CCLicense] = None age_min: Optional[int] = Field(None, ge=3, le=18) age_max: Optional[int] = Field(None, ge=3, le=18) embed_url: Optional[str] = None tags: Optional[List[str]] = None status: Optional[ContentStatus] = None class RatingCreate(BaseModel): """Schema für Rating Creation""" stars: int = Field(..., ge=1, le=5) comment: Optional[str] = Field(None, max_length=2000) # ============= RESPONSE SCHEMAS ============= class TagResponse(BaseModel): """Tag Response""" id: str name: str category: Optional[str] class Config: from_attributes = True class RatingResponse(BaseModel): """Rating Response""" id: str user_id: str user_name: Optional[str] stars: int comment: Optional[str] created_at: datetime class Config: from_attributes = True class ContentResponse(BaseModel): """Content Response (Full)""" id: str creator_id: str creator_name: str creator_email: Optional[str] title: str description: Optional[str] content_type: ContentType category: ContentCategory license: CCLicense age_min: int age_max: int files: List[str] thumbnail_url: Optional[str] embed_url: Optional[str] h5p_content_id: Optional[str] matrix_room_id: Optional[str] matrix_event_id: Optional[str] status: ContentStatus downloads: int views: int avg_rating: float rating_count: int impact_score: float created_at: datetime updated_at: datetime published_at: Optional[datetime] tags: List[TagResponse] = [] class Config: from_attributes = True class ContentListItem(BaseModel): """Content Response (List View - simplified)""" id: str creator_name: str title: str description: Optional[str] content_type: ContentType category: ContentCategory license: CCLicense thumbnail_url: Optional[str] avg_rating: float rating_count: int downloads: int created_at: datetime tags: List[str] = [] class Config: from_attributes = True class ContentWithRatings(ContentResponse): """Content with ratings included""" ratings: List[RatingResponse] = [] class Config: from_attributes = True # ============= FILTER SCHEMAS ============= class ContentFilter(BaseModel): """Search/Filter Parameters""" search: Optional[str] = None category: Optional[ContentCategory] = None content_type: Optional[ContentType] = None license: Optional[CCLicense] = None age_min: Optional[int] = None age_max: Optional[int] = None tags: Optional[List[str]] = None min_rating: Optional[float] = None status: Optional[ContentStatus] = ContentStatus.PUBLISHED creator_id: Optional[str] = None # Pagination skip: int = Field(0, ge=0) limit: int = Field(20, ge=1, le=100) # Sorting sort_by: str = Field("created_at", pattern="^(created_at|avg_rating|downloads|title)$") sort_desc: bool = True # ============= ANALYTICS SCHEMAS ============= class ContentStats(BaseModel): """Content Statistics""" total_contents: int total_downloads: int total_views: int avg_rating: float by_category: dict by_type: dict by_license: dict class CreatorStats(BaseModel): """Creator Statistics""" creator_id: str creator_name: str total_contents: int total_downloads: int total_views: int avg_rating: float impact_score: float content_breakdown: dict # ============= UPLOAD SCHEMAS ============= class FileUploadResponse(BaseModel): """File Upload Response""" file_url: str file_name: str file_size: int content_type: str