first commit
This commit is contained in:
53
app/services/badges.py
Normal file
53
app/services/badges.py
Normal file
@@ -0,0 +1,53 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from collections import defaultdict
|
||||
from datetime import date, timedelta
|
||||
|
||||
from ..models import BadgeDefinition, TaskInstance
|
||||
|
||||
|
||||
def _max_day_streak(days: set[date]) -> int:
|
||||
if not days:
|
||||
return 0
|
||||
streak = 1
|
||||
best = 1
|
||||
ordered = sorted(days)
|
||||
for previous, current in zip(ordered, ordered[1:]):
|
||||
if current == previous + timedelta(days=1):
|
||||
streak += 1
|
||||
else:
|
||||
streak = 1
|
||||
best = max(best, streak)
|
||||
return best
|
||||
|
||||
|
||||
def compute_badge_awards(definitions: list[BadgeDefinition], completed_tasks: list[TaskInstance]) -> list[dict]:
|
||||
by_type: dict[str, int] = defaultdict(int)
|
||||
completion_days: set[date] = set()
|
||||
|
||||
for task in completed_tasks:
|
||||
if not task.completed_at:
|
||||
continue
|
||||
completion_day = task.completed_at.date()
|
||||
completion_days.add(completion_day)
|
||||
by_type["monthly_task_count"] += 1
|
||||
if task.due_date and completion_day < task.due_date:
|
||||
by_type["early_finisher_count"] += 1
|
||||
if task.due_date and completion_day <= task.due_date:
|
||||
by_type["on_time_count"] += 1
|
||||
|
||||
by_type["streak_days"] = _max_day_streak(completion_days)
|
||||
|
||||
awards = []
|
||||
for definition in definitions:
|
||||
metric_value = by_type.get(definition.trigger_type, 0)
|
||||
if definition.active and metric_value >= definition.threshold:
|
||||
awards.append(
|
||||
{
|
||||
"definition": definition,
|
||||
"metric_value": metric_value,
|
||||
"bonus_points": definition.bonus_points,
|
||||
}
|
||||
)
|
||||
return awards
|
||||
|
||||
Reference in New Issue
Block a user