from pydantic import BaseModel from typing import Optional, List from datetime import datetime from enum import Enum class IssueTypeEnum(str, Enum): MEETING = "meeting" SUPPORT = "support" ISSUE = "issue" MAINTENANCE = "maintenance" RESEARCH = "research" REVIEW = "review" STORY = "story" TEST = "test" RESOLUTION = "resolution" TASK = "task" # legacy class IssueStatusEnum(str, Enum): OPEN = "open" IN_PROGRESS = "in_progress" RESOLVED = "resolved" CLOSED = "closed" BLOCKED = "blocked" class IssuePriorityEnum(str, Enum): LOW = "low" MEDIUM = "medium" HIGH = "high" CRITICAL = "critical" # Issue schemas class IssueBase(BaseModel): title: str description: Optional[str] = None issue_type: IssueTypeEnum = IssueTypeEnum.ISSUE issue_subtype: Optional[str] = None priority: IssuePriorityEnum = IssuePriorityEnum.MEDIUM tags: Optional[str] = None depends_on_id: Optional[int] = None due_date: Optional[datetime] = None milestone_id: Optional[int] = None class IssueCreate(IssueBase): project_id: int reporter_id: int assignee_id: Optional[int] = None # Resolution specific resolution_summary: Optional[str] = None positions: Optional[str] = None pending_matters: Optional[str] = None class IssueUpdate(BaseModel): title: Optional[str] = None description: Optional[str] = None issue_type: Optional[IssueTypeEnum] = None issue_subtype: Optional[str] = None status: Optional[IssueStatusEnum] = None priority: Optional[IssuePriorityEnum] = None assignee_id: Optional[int] = None tags: Optional[str] = None depends_on_id: Optional[int] = None due_date: Optional[datetime] = None milestone_id: Optional[int] = None # Resolution specific resolution_summary: Optional[str] = None positions: Optional[str] = None pending_matters: Optional[str] = None class IssueResponse(IssueBase): id: int status: IssueStatusEnum project_id: int reporter_id: int assignee_id: Optional[int] resolution_summary: Optional[str] positions: Optional[str] pending_matters: Optional[str] due_date: Optional[datetime] = None milestone_id: Optional[int] = None created_at: datetime updated_at: Optional[datetime] class Config: from_attributes = True # Comment schemas class CommentBase(BaseModel): content: str class CommentCreate(CommentBase): issue_id: int author_id: int class CommentUpdate(BaseModel): content: Optional[str] = None class CommentResponse(CommentBase): id: int issue_id: int author_id: int created_at: datetime updated_at: Optional[datetime] 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 class _ProjectResponse_Inactive(ProjectBase): id: int owner_id: int project_code: str | None = None created_at: datetime class Config: from_attributes = True # 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): 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