from typing import List, Optional from pydantic import BaseModel, Field, validator from datetime import datetime, timezone from tools.datetime import epoch_get from enum import Enum import json class TaskCategory(str, Enum): BUG = "bug" QUESTION = "question" STORY = "story" TASK = "task" VARIA = "varia" FEATURE = "feature" class TaskStatus(str, Enum): NEW = "new" PROGRESS = "progress" TEST = "test" DONE = "done" BLOCKED = "blocked" class TaskRemark(BaseModel): remark: str timestamp: int = Field(default_factory=lambda: int(datetime.now(timezone.utc).timestamp())) tracked_hours: Optional[float] = None assignee: Optional[int] = None def get_formatted_timestamp(self) -> str: return datetime.fromtimestamp(self.timestamp, tz=timezone.utc).strftime('%Y-%m-%d %H:%M:%S UTC') class Task(BaseModel): id: int name: str description: str category: TaskCategory status: TaskStatus = Field(default=TaskStatus.NEW) priority: int = Field(default=1, ge=1, le=5) created_at: int = Field(default_factory=lambda: int(datetime.now(timezone.utc).timestamp())) deadline: Optional[int] = None assignees: List[int] = [] tags: List[str] = [] remarks: List[TaskRemark] = [] estimated_hours: Optional[float] = None actual_hours: Optional[float] = None parent_task_id: Optional[int] = None subtasks: List[int] = [] @validator('deadline') def check_deadline(cls, v): if v is not None and v < int(datetime.now(timezone.utc).timestamp()): raise ValueError('Deadline cannot be in the past') return v def is_overdue(self) -> bool: if self.deadline is None: return False return int(datetime.now(timezone.utc).timestamp()) > self.deadline def get_formatted_deadline(self) -> Optional[str]: if self.deadline is None: return None return datetime.fromtimestamp(self.deadline, tz=timezone.utc).strftime('%Y-%m-%d %H:%M:%S UTC') def add_remark(self, remark: str, tracked_hours: Optional[float] = None, assignee: Optional[int] = None): self.remarks.append(TaskRemark(remark=remark, tracked_hours=tracked_hours, assignee=assignee)) def get_total_tracked_hours(self) -> float: return sum(remark.tracked_hours or 0 for remark in self.remarks) def deadline_set(self, deadline: str): """ support +1h (hours), +2d (days), +1w (week), +1m (month) support 20/10/2024 and 20/10 and 20/10/24 (all same day) if hour not specified then midday (noon) """ self.deadline = epoch_get(deadline) class TaskList(BaseModel): tasks: List[Task] = [] def add_task(self, task: Task): self.tasks.append(task) def get_tasks(self): return self.tasks def get_task_by_id(self, task_id: int) -> Task: task = next((task for task in self.tasks if task.id == task_id), None) if task: return task raise Exception(f"Can't find task {task_id}") def new(jsondata: str = "") -> TaskList: if not jsondata: return example() try: data = json.loads(jsondata) return TaskList(**data) except json.JSONDecodeError: raise ValueError("Invalid JSON input") except Exception as e: raise ValueError(f"Error creating TaskList from JSON: {str(e)}") return data def example() -> TaskList: task_list = TaskList() # Create 10 tasks with different properties tasks = [ Task( id=1, name="Implement user authentication", description="Develop and integrate user authentication system", category=TaskCategory.FEATURE, status=TaskStatus.PROGRESS, priority=4, deadline=epoch_get("+5d"), assignees=[101, 102], tags=["security", "backend"], estimated_hours=40, ), Task( id=2, name="Design landing page", description="Create a responsive design for the website landing page", category=TaskCategory.TASK, status=TaskStatus.NEW, priority=3, deadline=epoch_get("15/09/2023"), assignees=[203], tags=["frontend", "ui/ux"], estimated_hours=20, ), Task( id=3, name="Database optimization", description="Optimize database queries for improved performance", category=TaskCategory.TASK, status=TaskStatus.NEW, priority=2, deadline=epoch_get("+2w"), assignees=[104], tags=["performance", "backend"], estimated_hours=15, ), Task( id=4, name="Write user documentation", description="Create comprehensive user guide for the new features", category=TaskCategory.TASK, status=TaskStatus.NEW, priority=1, deadline=epoch_get("+1m"), assignees=[305], tags=["writing", "user-support"], estimated_hours=25, ), Task( id=5, name="Implement payment gateway", description="Integrate third-party payment gateway for online transactions", category=TaskCategory.FEATURE, status=TaskStatus.PROGRESS, priority=5, deadline=epoch_get("+10d"), assignees=[106, 107], tags=["payment", "security", "backend"], estimated_hours=50, ), Task( id=6, name="Mobile app UI redesign", description="Redesign the mobile app user interface for better user experience", category=TaskCategory.TASK, status=TaskStatus.NEW, priority=3, deadline=epoch_get("30/09/2023"), assignees=[208], tags=["mobile", "ui/ux"], estimated_hours=35, ), Task( id=7, name="Setup CI/CD pipeline", description="Configure continuous integration and deployment pipeline", category=TaskCategory.TASK, status=TaskStatus.PROGRESS, priority=4, deadline=epoch_get("+1w"), assignees=[109], tags=["automation", "deployment"], estimated_hours=30, ), Task( id=8, name="Conduct user acceptance testing", description="Organize and conduct UAT for the new features", category=TaskCategory.TASK, status=TaskStatus.NEW, priority=2, deadline=epoch_get("+3w"), assignees=[210, 311], tags=["testing", "user-feedback"], estimated_hours=40, ), Task( id=9, name="Implement data analytics dashboard", description="Create a dashboard to visualize key performance metrics", category=TaskCategory.FEATURE, status=TaskStatus.NEW, priority=3, deadline=epoch_get("+20d"), assignees=[112, 213], tags=["analytics", "frontend", "data-visualization"], estimated_hours=60, ), Task( id=10, name="Optimize SEO", description="Implement SEO best practices to improve search engine rankings", category=TaskCategory.TASK, status=TaskStatus.NEW, priority=2, deadline=epoch_get("31/10/2023"), assignees=[314], tags=["seo", "marketing"], estimated_hours=25, ), ] # Add tasks to the TaskList for task in tasks: task_list.add_task(task) # Add some remarks to tasks task_list.get_task_by_id(1).add_remark("Started working on user registration flow", tracked_hours=4.5, assignee=101) task_list.get_task_by_id(5).add_remark("Completed integration with PayPal API", tracked_hours=8, assignee=106) task_list.get_task_by_id(7).add_remark("Jenkins pipeline configured, working on Docker integration", tracked_hours=6, assignee=109) # Print some information about the tasks for task in task_list.get_tasks(): print(f"Task ID: {task.id}") print(f"Name: {task.name}") print(f"Category: {task.category.value}") print(f"Status: {task.status.value}") print(f"Priority: {task.priority}") print(f"Deadline: {task.get_formatted_deadline()}") print(f"Assignees: {task.assignees}") print(f"Tags: {task.tags}") print(f"Estimated hours: {task.estimated_hours}") print(f"Total tracked hours: {task.get_total_tracked_hours()}") print("Remarks:") for remark in task.remarks: print(f" - {remark.remark} (Hours: {remark.tracked_hours}, Assignee: {remark.assignee})") print("---") return task_list if __name__ == "__main__": task_list = new() print(task_list)