from pydantic import BaseModel, Field from typing import Optional, List from datetime import date, datetime from enum import Enum from models.task import TaskType, TaskStatus, ReviewDecision, AttachmentType from models.user import DepartmentRole class TaskBase(BaseModel): name: str = Field(..., min_length=1, max_length=255) description: Optional[str] = None task_type: str # Changed from TaskType enum to str to support custom task types deadline: Optional[date] = None status: str = "not_started" # Changed from TaskStatus enum to str to support custom statuses class TaskCreate(TaskBase): project_id: int episode_id: Optional[int] = None shot_id: Optional[int] = None asset_id: Optional[int] = None assigned_user_id: Optional[int] = None class TaskUpdate(BaseModel): name: Optional[str] = Field(None, min_length=1, max_length=255) description: Optional[str] = None task_type: Optional[str] = None # Changed from TaskType enum to str to support custom task types deadline: Optional[date] = None status: Optional[str] = None # Changed from TaskStatus enum to str to support custom statuses assigned_user_id: Optional[int] = None class TaskStatusUpdate(BaseModel): status: str # Changed from TaskStatus enum to str to support custom statuses class TaskAssignment(BaseModel): assigned_user_id: int class TaskResponse(TaskBase): id: int project_id: int episode_id: Optional[int] = None shot_id: Optional[int] = None asset_id: Optional[int] = None assigned_user_id: Optional[int] = None created_at: datetime updated_at: datetime # Related entity names for display project_name: Optional[str] = None episode_name: Optional[str] = None shot_name: Optional[str] = None asset_name: Optional[str] = None assigned_user_name: Optional[str] = None assigned_user_email: Optional[str] = None assigned_user_avatar_url: Optional[str] = None class Config: from_attributes = True class TaskListResponse(BaseModel): id: int name: str task_type: str # Changed from TaskType enum to str to support custom task types status: str # Changed from TaskStatus enum to str to support custom statuses deadline: Optional[date] = None project_id: int project_name: str episode_id: Optional[int] = None episode_name: Optional[str] = None shot_id: Optional[int] = None shot_name: Optional[str] = None asset_id: Optional[int] = None asset_name: Optional[str] = None assigned_user_id: Optional[int] = None assigned_user_name: Optional[str] = None assigned_user_avatar_url: Optional[str] = None created_at: datetime updated_at: datetime class Config: from_attributes = True # Production Notes schemas class ProductionNoteBase(BaseModel): content: str = Field(..., min_length=1) parent_note_id: Optional[int] = None class ProductionNoteCreate(ProductionNoteBase): pass class ProductionNoteUpdate(BaseModel): content: str = Field(..., min_length=1) class ProductionNoteResponse(ProductionNoteBase): id: int task_id: int user_id: int created_at: datetime updated_at: datetime # User information user_first_name: str user_last_name: str user_email: str user_avatar_url: Optional[str] = None # Child notes for threading child_notes: Optional[List['ProductionNoteResponse']] = None class Config: from_attributes = True # Task Attachment schemas class TaskAttachmentBase(BaseModel): file_name: str attachment_type: AttachmentType = AttachmentType.REFERENCE description: Optional[str] = None class TaskAttachmentCreate(TaskAttachmentBase): pass class TaskAttachmentResponse(TaskAttachmentBase): id: int task_id: int user_id: int file_path: str file_type: str file_size: int uploaded_at: datetime # User information user_first_name: str user_last_name: str # File serving URLs (computed properties) download_url: Optional[str] = None thumbnail_url: Optional[str] = None class Config: from_attributes = True # Submission schemas class SubmissionBase(BaseModel): notes: Optional[str] = None class SubmissionCreate(SubmissionBase): pass class SubmissionResponse(SubmissionBase): id: int task_id: int user_id: int file_path: str file_name: str version_number: int submitted_at: datetime # User information user_first_name: str user_last_name: str # Latest review if any latest_review: Optional['ReviewResponse'] = None # File serving URLs (computed properties) download_url: Optional[str] = None thumbnail_url: Optional[str] = None stream_url: Optional[str] = None class Config: from_attributes = True # Review schemas class ReviewBase(BaseModel): decision: ReviewDecision feedback: Optional[str] = None class ReviewCreate(ReviewBase): pass class ReviewResponse(ReviewBase): id: int submission_id: int reviewer_id: int reviewed_at: datetime # Reviewer information reviewer_first_name: str reviewer_last_name: str class Config: from_attributes = True # Bulk action schemas class BulkStatusUpdate(BaseModel): task_ids: List[int] = Field(..., min_length=1) status: TaskStatus class BulkAssignment(BaseModel): task_ids: List[int] = Field(..., min_length=1) assigned_user_id: int class BulkActionResult(BaseModel): success_count: int failed_count: int errors: Optional[List[dict]] = None # Update forward references ProductionNoteResponse.model_rebuild() SubmissionResponse.model_rebuild()