feat: add persistent badges and admin badge page

This commit is contained in:
2026-04-13 10:19:38 +02:00
parent 3c99c3683e
commit c36abe82a8
27 changed files with 576 additions and 100 deletions

View File

@@ -3,11 +3,9 @@ from __future__ import annotations
from collections import defaultdict
from datetime import datetime
from sqlalchemy import extract, select
from ..extensions import db
from ..models import BadgeDefinition, MonthlyScoreSnapshot, TaskInstance, User
from .badges import compute_badge_awards
from ..models import MonthlyScoreSnapshot, TaskInstance, User
from .badges import badge_awards_for_month, evaluate_monthly_badges
from .dates import local_now, month_bounds, next_month, previous_month
@@ -21,7 +19,6 @@ def _build_ranking(rows: list[dict]) -> list[dict]:
def compute_monthly_scores(year: int, month: int) -> list[dict]:
start, end = month_bounds(year, month)
users = User.query.order_by(User.name.asc()).all()
badges = BadgeDefinition.query.filter_by(active=True).all()
completed_tasks = TaskInstance.query.filter(
TaskInstance.completed_at.isnot(None),
TaskInstance.completed_at >= start,
@@ -37,8 +34,8 @@ def compute_monthly_scores(year: int, month: int) -> list[dict]:
for user in users:
personal_tasks = tasks_by_user.get(user.id, [])
base_points = sum(task.points_awarded for task in personal_tasks)
awards = compute_badge_awards(badges, personal_tasks)
bonus_points = sum(award["bonus_points"] for award in awards)
earned_badges = badge_awards_for_month(user.id, year, month)
bonus_points = sum(badge.badge_definition.bonus_points for badge in earned_badges if badge.badge_definition.active)
rows.append(
{
"user": user,
@@ -46,7 +43,7 @@ def compute_monthly_scores(year: int, month: int) -> list[dict]:
"bonus_points": bonus_points,
"total_points": base_points + bonus_points,
"completed_tasks_count": len(personal_tasks),
"badges": awards,
"badges": earned_badges,
}
)
return _build_ranking(rows)
@@ -100,6 +97,7 @@ def archive_months_missing_up_to_previous() -> None:
)
)
db.session.commit()
evaluate_monthly_badges(year, month)
year, month = next_month(year, month)
@@ -120,4 +118,3 @@ def get_snapshot_rows(year: int, month: int) -> list[MonthlyScoreSnapshot]:
.order_by(MonthlyScoreSnapshot.rank.asc(), MonthlyScoreSnapshot.total_points.desc())
.all()
)