feat: add shared task assignments and quick win sorting

This commit is contained in:
2026-04-15 13:18:50 +02:00
parent f8f3641811
commit 4233175067
18 changed files with 414 additions and 55 deletions

View File

@@ -35,12 +35,24 @@ class User(UserMixin, TimestampMixin, db.Model):
backref="default_assigned_user",
lazy=True,
)
secondary_assigned_task_templates = db.relationship(
"TaskTemplate",
foreign_keys="TaskTemplate.default_assigned_user_secondary_id",
backref="default_assigned_user_secondary",
lazy=True,
)
assigned_tasks = db.relationship(
"TaskInstance",
foreign_keys="TaskInstance.assigned_user_id",
backref="assigned_user",
lazy=True,
)
secondary_assigned_tasks = db.relationship(
"TaskInstance",
foreign_keys="TaskInstance.assigned_user_secondary_id",
backref="assigned_user_secondary",
lazy=True,
)
completed_tasks = db.relationship(
"TaskInstance",
foreign_keys="TaskInstance.completed_by_user_id",
@@ -87,6 +99,7 @@ class TaskTemplate(TimestampMixin, db.Model):
description = db.Column(db.Text, nullable=True)
default_points = db.Column(db.Integer, nullable=False, default=10)
default_assigned_user_id = db.Column(db.Integer, db.ForeignKey("user.id"), nullable=True)
default_assigned_user_secondary_id = db.Column(db.Integer, db.ForeignKey("user.id"), nullable=True)
recurrence_interval_value = db.Column(db.Integer, nullable=True)
recurrence_interval_unit = db.Column(db.String(20), nullable=False, default="none")
active = db.Column(db.Boolean, nullable=False, default=True)
@@ -113,6 +126,7 @@ class QuickWin(TimestampMixin, db.Model):
effort = db.Column(db.String(40), nullable=False, index=True)
active = db.Column(db.Boolean, nullable=False, default=True)
created_by_user_id = db.Column(db.Integer, db.ForeignKey("user.id"), nullable=False, index=True)
sort_order = db.Column(db.Integer, nullable=False, default=0, index=True)
class TaskInstance(TimestampMixin, db.Model):
@@ -121,6 +135,7 @@ class TaskInstance(TimestampMixin, db.Model):
title = db.Column(db.String(160), nullable=False)
description = db.Column(db.Text, nullable=True)
assigned_user_id = db.Column(db.Integer, db.ForeignKey("user.id"), nullable=True, index=True)
assigned_user_secondary_id = db.Column(db.Integer, db.ForeignKey("user.id"), nullable=True, index=True)
due_date = db.Column(db.Date, nullable=False, index=True)
status = db.Column(db.String(20), nullable=False, default="open", index=True)
completed_at = db.Column(db.DateTime, nullable=True, index=True)
@@ -131,21 +146,50 @@ class TaskInstance(TimestampMixin, db.Model):
def is_completed(self) -> bool:
return self.completed_at is not None
@property
def assigned_users(self) -> list[User]:
users: list[User] = []
if self.assigned_user:
users.append(self.assigned_user)
if self.assigned_user_secondary and self.assigned_user_secondary.id not in {user.id for user in users}:
users.append(self.assigned_user_secondary)
return users
@property
def assigned_user_ids(self) -> list[int]:
return [user.id for user in self.assigned_users]
@property
def is_shared_assignment(self) -> bool:
return self.assigned_user_id is not None and self.assigned_user_secondary_id is not None
@property
def assignee_label(self) -> str:
if not self.assigned_users:
return "Ohne Person"
return " & ".join(user.name for user in self.assigned_users)
def compute_status(self, reference_date: date | None = None) -> str:
reference_date = reference_date or date.today()
if self.completed_at:
return "completed"
if self.due_date < reference_date:
return "overdue"
if self.due_date <= reference_date + timedelta(days=2):
return "soon"
if self.due_date == reference_date:
return "due_today"
if self.due_date == reference_date + timedelta(days=1):
return "due_tomorrow"
if self.due_date == reference_date + timedelta(days=2):
return "due_day_after_tomorrow"
return "open"
@property
def status_label(self) -> str:
labels = {
"open": "Offen",
"soon": "Bald fällig",
"due_today": "Bald fällig",
"due_tomorrow": "Morgen fällig",
"due_day_after_tomorrow": "Übermorgen fällig",
"overdue": "Überfällig",
"completed": "Erledigt",
}