""" Gitea domain models. These models represent the core entities in Gitea and provide a clean interface independent of the underlying API representation. """ from dataclasses import dataclass from datetime import datetime from enum import Enum from typing import List, Optional, Dict, Any class ProjectState(Enum): """Standard project states using labels.""" TODO = "status:todo" ACTIVE = "status:active" REVIEW = "status:review" DONE = "status:done" BLOCKED = "status:blocked" class Priority(Enum): """Priority levels using labels.""" LOW = "priority:low" MEDIUM = "priority:medium" HIGH = "priority:high" CRITICAL = "priority:critical" @dataclass class Label: """Represents a Gitea issue label.""" id: int name: str color: str description: str = "" @dataclass class User: """Represents a Gitea user.""" id: int login: str full_name: str = "" email: str = "" avatar_url: str = "" @dataclass class Milestone: """Represents a Gitea milestone (used as projects).""" id: int title: str description: str state: str # 'open' or 'closed' open_issues: int closed_issues: int due_on: Optional[str] = None created_at: Optional[datetime] = None updated_at: Optional[datetime] = None @dataclass class Issue: """Represents a Gitea issue.""" number: int title: str body: str state: str # 'open' or 'closed' created_at: datetime updated_at: datetime html_url: str assignee: Optional[User] = None labels: List[Label] = None milestone: Optional[Milestone] = None def __post_init__(self): if self.labels is None: self.labels = [] @property def priority(self) -> Optional[str]: """Get issue priority from labels.""" for label in self.labels: if label.name.startswith('priority:'): return label.name.replace('priority:', '') return None @property def status(self) -> Optional[str]: """Get issue status from labels.""" for label in self.labels: if label.name.startswith('status:'): return label.name.replace('status:', '') return None def has_label(self, label_name: str) -> bool: """Check if issue has a specific label.""" return any(label.name == label_name for label in self.labels) def has_priority(self, priority: Priority) -> bool: """Check if issue has a specific priority.""" return self.has_label(priority.value) def has_status(self, status: ProjectState) -> bool: """Check if issue has a specific status.""" return self.has_label(status.value) @dataclass class IssueCreateData: """Data for creating a new issue.""" title: str body: str = "" assignees: List[str] = None milestone: Optional[int] = None labels: List[str] = None def __post_init__(self): if self.assignees is None: self.assignees = [] if self.labels is None: self.labels = [] @dataclass class IssueUpdateData: """Data for updating an existing issue.""" title: Optional[str] = None body: Optional[str] = None state: Optional[str] = None assignees: Optional[List[str]] = None milestone: Optional[int] = None labels: Optional[List[str]] = None @dataclass class MilestoneCreateData: """Data for creating a new milestone.""" title: str description: str = "" due_on: Optional[str] = None @dataclass class LabelCreateData: """Data for creating a new label.""" name: str color: str description: str = ""