Files
LinkDesk/backend/schemas/task.py
T
indigo c09710f4e5 Add per-project Department management
Departments are now a customizable per-project list (standard + custom),
matching the existing custom task type/status pattern, instead of a fixed
7-value enum. They're usable directly on tasks (new field, independent of
assignee) and continue to drive team member department roles.
2026-07-22 04:03:33 +08:00

252 lines
6.5 KiB
Python

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, NoteType
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
start_date: Optional[date] = None
deadline: Optional[date] = None
status: str = "not_started" # Changed from TaskStatus enum to str to support custom statuses
department: Optional[str] = None # Standard or project-custom department, independent of assignee
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
start_date: Optional[date] = None
deadline: Optional[date] = None
status: Optional[str] = None # Changed from TaskStatus enum to str to support custom statuses
department: Optional[str] = None # Standard or project-custom department, independent of assignee
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
department: Optional[str] = None # Standard or project-custom department, independent of assignee
start_date: Optional[date] = None
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):
note_type: NoteType = NoteType.INTERNAL
class ProductionNoteUpdate(BaseModel):
content: str = Field(..., min_length=1)
class ProductionNoteResponse(ProductionNoteBase):
id: int
task_id: int
user_id: int
note_type: NoteType
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 SubmissionUpdate(BaseModel):
notes: Optional[str] = None
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
class SubmissionDateInfo(BaseModel):
"""Minimal per-task submission date, for lightweight bulk lookups (e.g. Gantt markers)."""
task_id: int
submitted_at: datetime
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: str # Changed from TaskStatus enum to str to support custom statuses
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()