Source code for issuedb.models

"""Data models and enums for IssueDB."""

from dataclasses import dataclass, field
from datetime import datetime
from enum import Enum
from typing import Any, Optional


[docs] class Priority(Enum): """Priority levels for issues.""" LOW = "low" MEDIUM = "medium" HIGH = "high" CRITICAL = "critical"
[docs] @classmethod def from_string(cls, value: str) -> "Priority": """Create Priority from string value.""" try: return cls(value.lower()) except ValueError: raise ValueError( f"Invalid priority: {value}. Must be one of: {', '.join([p.value for p in cls])}" ) from None
[docs] def to_int(self) -> int: """Convert priority to integer for sorting (higher number = higher priority).""" priority_map = { Priority.LOW: 1, Priority.MEDIUM: 2, Priority.HIGH: 3, Priority.CRITICAL: 4, } return priority_map[self]
[docs] class Status(Enum): """Status levels for issues.""" OPEN = "open" IN_PROGRESS = "in-progress" CLOSED = "closed" WONT_DO = "wont-do"
[docs] @classmethod def from_string(cls, value: str) -> "Status": """Create Status from string value.""" try: return cls(value.lower()) except ValueError: raise ValueError( f"Invalid status: {value}. Must be one of: {', '.join([s.value for s in cls])}" ) from None
[docs] @dataclass class Comment: """Represents a comment on an issue.""" id: Optional[int] = field(default=None) issue_id: int = field(default=0) text: str = field(default="") created_at: datetime = field(default_factory=datetime.now)
[docs] def to_dict(self) -> dict[str, Any]: """Convert comment to dictionary for JSON serialization.""" return { "id": self.id, "issue_id": self.issue_id, "text": self.text, "created_at": self.created_at.isoformat() if self.created_at else None, }
[docs] @dataclass class AuditLog: """Represents an audit log entry for tracking changes.""" id: Optional[int] = field(default=None) issue_id: int = field(default=0) action: str = field(default="") # CREATE, UPDATE, DELETE field_name: Optional[str] = field(default=None) old_value: Optional[str] = field(default=None) new_value: Optional[str] = field(default=None) timestamp: datetime = field(default_factory=datetime.now)
[docs] def to_dict(self) -> dict[str, Any]: """Convert audit log to dictionary for JSON serialization.""" return { "id": self.id, "issue_id": self.issue_id, "action": self.action, "field_name": self.field_name, "old_value": self.old_value, "new_value": self.new_value, "timestamp": self.timestamp.isoformat() if self.timestamp else None, }
@dataclass class IssueLink: """Represents a link between an issue and a git commit or branch.""" id: Optional[int] = field(default=None) issue_id: int = field(default=0) link_type: str = field(default="") # 'commit' or 'branch' reference: str = field(default="") # commit hash or branch name created_at: datetime = field(default_factory=datetime.now) def to_dict(self) -> dict[str, Any]: """Convert issue link to dictionary for JSON serialization.""" return { "id": self.id, "issue_id": self.issue_id, "link_type": self.link_type, "reference": self.reference, "created_at": self.created_at.isoformat() if self.created_at else None, } @dataclass class CodeReference: """Represents a reference to a file location in the codebase.""" id: Optional[int] = field(default=None) issue_id: int = field(default=0) file_path: str = field(default="") start_line: Optional[int] = field(default=None) end_line: Optional[int] = field(default=None) note: Optional[str] = field(default=None) created_at: datetime = field(default_factory=datetime.now) def to_dict(self) -> dict[str, Any]: """Convert code reference to dictionary for JSON serialization.""" return { "id": self.id, "issue_id": self.issue_id, "file_path": self.file_path, "start_line": self.start_line, "end_line": self.end_line, "note": self.note, "created_at": self.created_at.isoformat() if self.created_at else None, } @dataclass class Tag: """Represents a tag.""" id: Optional[int] = field(default=None) name: str = field(default="") color: Optional[str] = field(default=None) created_at: datetime = field(default_factory=datetime.now) def to_dict(self) -> dict[str, Any]: """Convert tag to dictionary.""" return { "id": self.id, "name": self.name, "color": self.color, "created_at": self.created_at.isoformat() if self.created_at else None, }
[docs] @dataclass class Issue: """Represents an issue in the tracking system.""" id: Optional[int] = field(default=None) title: str = field(default="") description: Optional[str] = field(default=None) priority: Priority = field(default=Priority.MEDIUM) status: Status = field(default=Status.OPEN) created_at: datetime = field(default_factory=datetime.now) updated_at: datetime = field(default_factory=datetime.now) estimated_hours: Optional[float] = field(default=None) due_date: Optional[datetime] = field(default=None) tags: list[Tag] = field(default_factory=list)
[docs] def to_dict(self) -> dict[str, Any]: """Convert issue to dictionary for JSON serialization.""" result: dict[str, Any] = { "id": self.id, "title": self.title, "description": self.description, "priority": self.priority.value, "status": self.status.value, "created_at": self.created_at.isoformat() if self.created_at else None, "updated_at": self.updated_at.isoformat() if self.updated_at else None, "tags": [tag.to_dict() for tag in self.tags], } if self.estimated_hours is not None: result["estimated_hours"] = self.estimated_hours if self.due_date: result["due_date"] = self.due_date.isoformat() return result
[docs] @classmethod def from_dict(cls, data: dict[str, Any]) -> "Issue": """Create Issue from dictionary.""" issue = cls() issue.id = data.get("id") issue.title = data.get("title", "") issue.description = data.get("description") if "priority" in data: issue.priority = Priority.from_string(data["priority"]) if "status" in data: issue.status = Status.from_string(data["status"]) if "created_at" in data and data["created_at"]: if isinstance(data["created_at"], str): issue.created_at = datetime.fromisoformat(data["created_at"]) else: issue.created_at = data["created_at"] if "updated_at" in data and data["updated_at"]: if isinstance(data["updated_at"], str): issue.updated_at = datetime.fromisoformat(data["updated_at"]) else: issue.updated_at = data["updated_at"] if "estimated_hours" in data: issue.estimated_hours = data.get("estimated_hours") if "due_date" in data and data["due_date"]: if isinstance(data["due_date"], str): issue.due_date = datetime.fromisoformat(data["due_date"]) else: issue.due_date = data["due_date"] if "tags" in data and isinstance(data["tags"], list): issue.tags = [] for tag_data in data["tags"]: tag = Tag( id=tag_data.get("id"), name=tag_data.get("name", ""), color=tag_data.get("color"), ) issue.tags.append(tag) return issue
@dataclass class Memory: """Represents a memory item.""" id: Optional[int] = field(default=None) key: str = field(default="") value: str = field(default="") category: str = field(default="general") created_at: datetime = field(default_factory=datetime.now) updated_at: datetime = field(default_factory=datetime.now) def to_dict(self) -> dict[str, Any]: """Convert memory to dictionary.""" return { "id": self.id, "key": self.key, "value": self.value, "category": self.category, "created_at": self.created_at.isoformat() if self.created_at else None, "updated_at": self.updated_at.isoformat() if self.updated_at else None, } @dataclass class LessonLearned: """Represents a lesson learned.""" id: Optional[int] = field(default=None) issue_id: Optional[int] = field(default=None) lesson: str = field(default="") category: str = field(default="general") created_at: datetime = field(default_factory=datetime.now) def to_dict(self) -> dict[str, Any]: """Convert lesson to dictionary.""" return { "id": self.id, "issue_id": self.issue_id, "lesson": self.lesson, "category": self.category, "created_at": self.created_at.isoformat() if self.created_at else None, } @dataclass class IssueRelation: """Represents a relationship between issues.""" id: Optional[int] = field(default=None) source_issue_id: int = field(default=0) target_issue_id: int = field(default=0) relation_type: str = field(default="") created_at: datetime = field(default_factory=datetime.now) def to_dict(self) -> dict[str, Any]: return { "id": self.id, "source_issue_id": self.source_issue_id, "target_issue_id": self.target_issue_id, "relation_type": self.relation_type, "created_at": self.created_at.isoformat() if self.created_at else None, } @dataclass class IssueTemplate: """Represents a template for creating issues with predefined settings.""" id: Optional[int] = field(default=None) name: str = field(default="") title_prefix: Optional[str] = field(default=None) default_priority: Optional[str] = field(default=None) default_status: Optional[str] = field(default=None) required_fields: list[str] = field(default_factory=list) # List of field names field_prompts: dict[str, str] = field(default_factory=dict) # Field name -> prompt text created_at: datetime = field(default_factory=datetime.now) def to_dict(self) -> dict[str, Any]: """Convert template to dictionary for JSON serialization.""" return { "id": self.id, "name": self.name, "title_prefix": self.title_prefix, "default_priority": self.default_priority, "default_status": self.default_status, "required_fields": self.required_fields, "field_prompts": self.field_prompts, "created_at": self.created_at.isoformat() if self.created_at else None, } @classmethod def from_dict(cls, data: dict[str, Any]) -> "IssueTemplate": """Create IssueTemplate from dictionary.""" template = cls() template.id = data.get("id") template.name = data.get("name", "") template.title_prefix = data.get("title_prefix") template.default_priority = data.get("default_priority") template.default_status = data.get("default_status") template.required_fields = data.get("required_fields", []) template.field_prompts = data.get("field_prompts", {}) if "created_at" in data and data["created_at"]: if isinstance(data["created_at"], str): template.created_at = datetime.fromisoformat(data["created_at"]) else: template.created_at = data["created_at"] return template