from pydantic import BaseModel from typing import Optional, List from datetime import datetime from enum import Enum class TaskTypeEnum(str, Enum): ISSUE = "issue" MAINTENANCE = "maintenance" RESEARCH = "research" REVIEW = "review" STORY = "story" TEST = "test" RESOLUTION = "resolution" TASK = "task" class TaskStatusEnum(str, Enum): OPEN = "open" PENDING = "pending" PROGRESSING = "progressing" CLOSED = "closed" class TaskPriorityEnum(str, Enum): LOW = "low" MEDIUM = "medium" HIGH = "high" CRITICAL = "critical" # Task schemas class TaskBase(BaseModel): title: str description: Optional[str] = None task_type: TaskTypeEnum = TaskTypeEnum.TASK task_subtype: Optional[str] = None priority: TaskPriorityEnum = TaskPriorityEnum.MEDIUM tags: Optional[str] = None estimated_effort: Optional[int] = None estimated_working_time: Optional[str] = None class TaskCreate(TaskBase): project_id: Optional[int] = None milestone_id: Optional[int] = None reporter_id: Optional[int] = None assignee_id: Optional[int] = None # Resolution specific resolution_summary: Optional[str] = None positions: Optional[str] = None pending_matters: Optional[str] = None class TaskUpdate(BaseModel): title: Optional[str] = None description: Optional[str] = None task_type: Optional[TaskTypeEnum] = None task_subtype: Optional[str] = None status: Optional[TaskStatusEnum] = None priority: Optional[TaskPriorityEnum] = None assignee_id: Optional[int] = None tags: Optional[str] = None estimated_effort: Optional[int] = None # Resolution specific resolution_summary: Optional[str] = None positions: Optional[str] = None pending_matters: Optional[str] = None class TaskResponse(TaskBase): id: int status: TaskStatusEnum task_code: Optional[str] = None project_id: int milestone_id: int reporter_id: int assignee_id: Optional[int] = None resolution_summary: Optional[str] = None positions: Optional[str] = None pending_matters: Optional[str] = None created_at: datetime updated_at: Optional[datetime] = None class Config: from_attributes = True # Comment schemas class CommentBase(BaseModel): content: str class CommentCreate(CommentBase): task_id: int author_id: int class CommentUpdate(BaseModel): content: Optional[str] = None class CommentResponse(CommentBase): id: int task_id: int author_id: int created_at: datetime updated_at: Optional[datetime] = None class Config: from_attributes = True # Project schemas class ProjectBase(BaseModel): name: str owner_name: Optional[str] = None description: Optional[str] = None sub_projects: Optional[list[str]] = None related_projects: Optional[list[str]] = None class ProjectCreate(ProjectBase): owner_id: int class ProjectUpdate(BaseModel): description: Optional[str] = None owner_name: Optional[str] = None sub_projects: Optional[list[str]] = None related_projects: Optional[list[str]] = None class ProjectResponse(BaseModel): id: int name: str owner_name: Optional[str] = None project_code: Optional[str] = None description: Optional[str] = None sub_projects: Optional[list[str]] = None related_projects: Optional[list[str]] = None owner_id: int created_at: datetime # User schemas class UserBase(BaseModel): username: str email: str full_name: Optional[str] = None class UserCreate(UserBase): password: Optional[str] = None is_admin: bool = False class UserResponse(UserBase): id: int is_active: bool is_admin: bool created_at: datetime class Config: from_attributes = True # Project Member schemas class ProjectMemberBase(BaseModel): user_id: int role: str = "dev" class ProjectMemberCreate(ProjectMemberBase): pass class ProjectMemberResponse(BaseModel): id: int user_id: int project_id: int role: str = "dev" class Config: from_attributes = True # Milestone schemas class MilestoneBase(BaseModel): title: str description: Optional[str] = None status: Optional[str] = "open" due_date: Optional[datetime] = None planned_release_date: Optional[datetime] = None depend_on_milestones: Optional[List[str]] = None depend_on_tasks: Optional[List[int]] = None class MilestoneCreate(MilestoneBase): project_id: Optional[int] = None pass class MilestoneUpdate(BaseModel): title: Optional[str] = None description: Optional[str] = None status: Optional[str] = None due_date: Optional[datetime] = None planned_release_date: Optional[datetime] = None depend_on_milestones: Optional[List[str]] = None depend_on_tasks: Optional[List[int]] = None class MilestoneResponse(MilestoneBase): id: int project_id: int created_at: datetime updated_at: Optional[datetime] = None class Config: from_attributes = True # Paginated response from typing import Generic, TypeVar T = TypeVar("T") class PaginatedResponse(BaseModel, Generic[T]): items: List[T] total: int page: int page_size: int total_pages: int