from __future__ import annotations import click from .extensions import db from .models import BadgeDefinition, User from .services.monthly import archive_months_missing_up_to_previous from .services.notifications import send_due_notifications, send_monthly_winner_notifications DEFAULT_BADGES = [ { "key": "first_wipe", "name": "Erster Wisch", "description": "Erledige deine erste Aufgabe.", "icon_name": "sparkles", "trigger_type": "first_task_completed", "threshold": 1, "bonus_points": 5, }, { "key": "warmed_up", "name": "Warmgelaufen", "description": "Erledige 10 Aufgaben insgesamt.", "icon_name": "fire", "trigger_type": "total_tasks_completed", "threshold": 10, "bonus_points": 10, }, { "key": "punctuality_pro", "name": "Pünktlichkeitsprofi", "description": "Erledige 10 Aufgaben pünktlich.", "icon_name": "check-double", "trigger_type": "on_time_tasks_completed", "threshold": 10, "bonus_points": 15, }, { "key": "early_bird", "name": "Der frühe Vogel", "description": "Erledige eine Aufgabe mindestens 1 Tag vor der Deadline.", "icon_name": "calendar-day", "trigger_type": "early_tasks_completed", "threshold": 1, "bonus_points": 8, }, { "key": "early_starter", "name": "Frühstarter", "description": "Erledige 5 Aufgaben mindestens 1 Tag vor der Deadline.", "icon_name": "rocket-launch", "trigger_type": "early_tasks_completed", "threshold": 5, "bonus_points": 15, }, { "key": "weekly_flow", "name": "Wochenflow", "description": "Erledige 7 Tage in Folge mindestens eine Aufgabe.", "icon_name": "flag-checkered", "trigger_type": "streak_days", "threshold": 7, "bonus_points": 20, }, { "key": "monthly_champion", "name": "Monatssieger", "description": "Gewinne einen Monat mit den meisten Punkten.", "icon_name": "trophy", "trigger_type": "monthly_win_count", "threshold": 1, "bonus_points": 25, }, { "key": "title_defender", "name": "Titelverteidiger", "description": "Gewinne 2 Monate in Folge.", "icon_name": "crown", "trigger_type": "consecutive_month_wins", "threshold": 2, "bonus_points": 30, }, { "key": "boss_battle", "name": "Bosskampf", "description": "Erledige eine Aufgabe mit besonders hohem Punktwert.", "icon_name": "bolt", "trigger_type": "high_point_task", "threshold": 25, "bonus_points": 12, }, { "key": "foreign_savior", "name": "Fremdretter", "description": "Erledige 5 Aufgaben, die ursprünglich jemand anderem zugewiesen waren.", "icon_name": "users-crown", "trigger_type": "foreign_tasks_completed", "threshold": 5, "bonus_points": 18, }, { "key": "white_glove", "name": "Weiße Weste", "description": "Bleibe einen ganzen Monat ohne überfällige Aufgabe.", "icon_name": "shield", "trigger_type": "clean_month", "threshold": 1, "bonus_points": 20, }, { "key": "comeback_kid", "name": "Comeback Kid", "description": "Gewinne nach einem verlorenen Monat den nächsten Monat.", "icon_name": "award", "trigger_type": "comeback_win", "threshold": 1, "bonus_points": 18, }, ] def seed_badges() -> None: wanted_keys = {payload["key"] for payload in DEFAULT_BADGES} BadgeDefinition.query.filter(~BadgeDefinition.key.in_(wanted_keys)).delete(synchronize_session=False) for payload in DEFAULT_BADGES: badge = BadgeDefinition.query.filter_by(key=payload["key"]).first() if not badge: db.session.add(BadgeDefinition(**payload)) continue badge.name = payload["name"] badge.description = payload["description"] badge.icon_name = payload["icon_name"] badge.trigger_type = payload["trigger_type"] badge.threshold = payload["threshold"] badge.bonus_points = payload["bonus_points"] badge.active = True db.session.commit() def register_cli(app) -> None: @app.cli.command("init-db") def init_db_command(): db.create_all() seed_badges() click.echo("Datenbank und Standard-Badges sind bereit.") @app.cli.command("create-user") @click.option("--name", prompt=True, help="Anzeigename") @click.option("--email", prompt=True, help="E-Mail") @click.option("--password", prompt=True, hide_input=True, confirmation_prompt=True, help="Passwort") def create_user_command(name: str, email: str, password: str): existing = User.query.filter_by(email=email.lower().strip()).first() if existing: click.echo("Es existiert bereits ein Nutzer mit dieser E-Mail.") raise SystemExit(1) user = User(name=name.strip(), email=email.lower().strip()) user.set_password(password) db.session.add(user) db.session.commit() click.echo(f"Nutzer {user.email} wurde angelegt.") @app.cli.command("archive-months") def archive_months_command(): archive_months_missing_up_to_previous() click.echo("Monatsarchiv wurde geprüft.") @app.cli.command("notify-due") def notify_due_command(): result = send_due_notifications() click.echo(f"Due-Push: sent={result.sent} skipped={result.skipped} failed={result.failed}") @app.cli.command("notify-monthly-winner") def notify_monthly_winner_command(): result = send_monthly_winner_notifications() click.echo(f"Winner-Push: sent={result.sent} skipped={result.skipped} failed={result.failed}")