feat: improve scheduled push notifications
This commit is contained in:
@@ -25,24 +25,30 @@ def _max_day_streak(days: set[date]) -> int:
|
||||
return best
|
||||
|
||||
|
||||
def award_badge(user: User, badge_key: str, *, awarded_at: datetime | None = None, context: dict | None = None) -> bool:
|
||||
def award_badge(
|
||||
user: User,
|
||||
badge_key: str,
|
||||
*,
|
||||
awarded_at: datetime | None = None,
|
||||
context: dict | None = None,
|
||||
) -> UserBadge | None:
|
||||
definition = BadgeDefinition.query.filter_by(key=badge_key, active=True).first()
|
||||
if not definition:
|
||||
return False
|
||||
return None
|
||||
|
||||
existing = UserBadge.query.filter_by(user_id=user.id, badge_definition_id=definition.id).first()
|
||||
if existing:
|
||||
return False
|
||||
return None
|
||||
|
||||
db.session.add(
|
||||
UserBadge(
|
||||
user_id=user.id,
|
||||
badge_definition_id=definition.id,
|
||||
awarded_at=awarded_at or datetime.utcnow(),
|
||||
context=json.dumps(context, sort_keys=True) if context else None,
|
||||
)
|
||||
award = UserBadge(
|
||||
user_id=user.id,
|
||||
badge_definition_id=definition.id,
|
||||
awarded_at=awarded_at or datetime.utcnow(),
|
||||
context=json.dumps(context, sort_keys=True) if context else None,
|
||||
)
|
||||
return True
|
||||
db.session.add(award)
|
||||
db.session.flush()
|
||||
return award
|
||||
|
||||
|
||||
def badge_awards_for_month(user_id: int, year: int, month: int) -> list[UserBadge]:
|
||||
@@ -101,20 +107,26 @@ def _completion_metrics(user: User) -> dict[str, int]:
|
||||
return metrics
|
||||
|
||||
|
||||
def evaluate_task_badges(user: User) -> list[str]:
|
||||
def evaluate_task_badges(user: User, *, notify: bool = False) -> list[UserBadge]:
|
||||
definitions = BadgeDefinition.query.filter_by(active=True).all()
|
||||
metrics = _completion_metrics(user)
|
||||
unlocked: list[str] = []
|
||||
unlocked: list[UserBadge] = []
|
||||
|
||||
for definition in definitions:
|
||||
metric_value = metrics.get(definition.trigger_type)
|
||||
if metric_value is None:
|
||||
continue
|
||||
if metric_value >= definition.threshold and award_badge(user, definition.key):
|
||||
unlocked.append(definition.name)
|
||||
if metric_value >= definition.threshold:
|
||||
award = award_badge(user, definition.key)
|
||||
if award:
|
||||
unlocked.append(award)
|
||||
|
||||
if unlocked:
|
||||
db.session.commit()
|
||||
if notify:
|
||||
from .notifications import send_badge_notifications_for_awards
|
||||
|
||||
send_badge_notifications_for_awards(unlocked)
|
||||
return unlocked
|
||||
|
||||
|
||||
@@ -151,31 +163,39 @@ def _winner_user_ids(year: int, month: int) -> set[int]:
|
||||
return {row.user_id for row in rows}
|
||||
|
||||
|
||||
def evaluate_monthly_badges(year: int, month: int) -> list[str]:
|
||||
def evaluate_monthly_badges(year: int, month: int, *, notify: bool = False) -> list[UserBadge]:
|
||||
award_time = _month_end_award_time(year, month)
|
||||
unlocked: list[str] = []
|
||||
unlocked: list[UserBadge] = []
|
||||
winners = _winner_user_ids(year, month)
|
||||
previous_year, previous_month_value = previous_month(year, month)
|
||||
previous_winners = _winner_user_ids(previous_year, previous_month_value)
|
||||
|
||||
for user in User.query.order_by(User.id.asc()).all():
|
||||
if user.id in winners:
|
||||
if award_badge(user, "monthly_champion", awarded_at=award_time, context={"year": year, "month": month}):
|
||||
unlocked.append(f"{user.name}: Monatssieger")
|
||||
award = award_badge(user, "monthly_champion", awarded_at=award_time, context={"year": year, "month": month})
|
||||
if award:
|
||||
unlocked.append(award)
|
||||
|
||||
if user.id in previous_winners:
|
||||
if award_badge(user, "title_defender", awarded_at=award_time, context={"year": year, "month": month}):
|
||||
unlocked.append(f"{user.name}: Titelverteidiger")
|
||||
award = award_badge(user, "title_defender", awarded_at=award_time, context={"year": year, "month": month})
|
||||
if award:
|
||||
unlocked.append(award)
|
||||
elif MonthlyScoreSnapshot.query.filter_by(year=previous_year, month=previous_month_value, user_id=user.id).first():
|
||||
if award_badge(user, "comeback_kid", awarded_at=award_time, context={"year": year, "month": month}):
|
||||
unlocked.append(f"{user.name}: Comeback Kid")
|
||||
award = award_badge(user, "comeback_kid", awarded_at=award_time, context={"year": year, "month": month})
|
||||
if award:
|
||||
unlocked.append(award)
|
||||
|
||||
if _user_had_clean_month(user.id, year, month):
|
||||
if award_badge(user, "white_glove", awarded_at=award_time, context={"year": year, "month": month}):
|
||||
unlocked.append(f"{user.name}: Weiße Weste")
|
||||
award = award_badge(user, "white_glove", awarded_at=award_time, context={"year": year, "month": month})
|
||||
if award:
|
||||
unlocked.append(award)
|
||||
|
||||
if unlocked:
|
||||
db.session.commit()
|
||||
if notify:
|
||||
from .notifications import send_badge_notifications_for_awards
|
||||
|
||||
send_badge_notifications_for_awards(unlocked)
|
||||
return unlocked
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user