heroweb/lib/webcomponents0/models/tasks.py
2024-09-01 20:00:13 +02:00

267 lines
8.9 KiB
Python

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)