Feature: Wetter-Tapferkeits-, Jahreszeiten- und Schnee-Badges (SW by-v693)

Drei neue Badge-Kategorien in achievements.py:
- wetter_tapfer: Diary-Einträge bei Regen/Kälte/Wind (precip>60, temp<2, wind>50)
- jahreszeiten: Anzahl Jahreszeiten mit mind. 5 Diary-Einträgen (max 4)
- schnee_held: Diary-Einträge bei Schnee (weathercode 71-77)

Beide Funktionen check_and_award und my_achievements erweitert.
This commit is contained in:
rene 2026-05-04 20:26:03 +02:00
parent 6bf088df56
commit d081029618

View file

@ -92,6 +92,45 @@ CATEGORIES = [
("gold", 10, "Wiki-Fotograf"),
],
},
{
"id": "wetter_tapfer",
"name": "Wetter-Tapferkeit",
"emoji": "⛈️",
"metrik": "wetter_tapfer_score",
"einheit": " Eintrag/Einträge",
"stufen": [
("bronze", 1, "Regentrotzdem"),
("silber", 5, "Wettertrotzer"),
("gold", 15, "Allwetter-Held"),
("platin", 30, "Hunde-Wetterheld"),
],
},
{
"id": "jahreszeiten",
"name": "Jahreszeiten-Erkunder",
"emoji": "🍃",
"metrik": "jahreszeiten_score",
"einheit": " Jahreszeit(en)",
"stufen": [
("bronze", 1, "Frühlings-Erkunder"),
("silber", 2, "Sommer-Genießer"),
("gold", 3, "Herbst-Schnüffler"),
("platin", 4, "Alle-Jahreszeiten"),
],
},
{
"id": "schnee_held",
"name": "Schneeheld",
"emoji": "❄️",
"metrik": "schnee_eintraege",
"einheit": " Eintrag/Einträge",
"stufen": [
("bronze", 1, "Erster Schnee"),
("silber", 5, "Schneehund"),
("gold", 15, "Schneeheld"),
("platin", 30, "Schneewolf"),
],
},
]
# Flat-Liste aller Badge-IDs für DB-Kompatibilität
@ -150,12 +189,47 @@ def check_and_award(user_id: int, conn):
"SELECT current_streak FROM users WHERE id=?", (user_id,)
).fetchone()
# Wetter-Tapferkeit: Diary-Einträge bei schlechtem Wetter
wetter_row = conn.execute("""
SELECT COUNT(*) AS cnt FROM diary d
LEFT JOIN diary_dogs dd ON dd.diary_id = d.id
WHERE d.user_id = ?
AND d.weather_json IS NOT NULL
AND (
CAST(json_extract(d.weather_json, '$.precip_prob') AS INTEGER) > 60
OR CAST(json_extract(d.weather_json, '$.temp_c') AS REAL) < 2
OR CAST(json_extract(d.weather_json, '$.wind_kmh') AS REAL) > 50
)
""", (user_id,)).fetchone()
# Jahreszeiten: Anzahl Jahreszeiten mit mind. 5 Diary-Einträgen
jahreszeiten_row = conn.execute("""
SELECT
(CASE WHEN (SELECT COUNT(*) FROM diary WHERE user_id=? AND CAST(strftime('%m', datum) AS INTEGER) IN (3,4,5)) >= 5 THEN 1 ELSE 0 END) +
(CASE WHEN (SELECT COUNT(*) FROM diary WHERE user_id=? AND CAST(strftime('%m', datum) AS INTEGER) IN (6,7,8)) >= 5 THEN 1 ELSE 0 END) +
(CASE WHEN (SELECT COUNT(*) FROM diary WHERE user_id=? AND CAST(strftime('%m', datum) AS INTEGER) IN (9,10,11)) >= 5 THEN 1 ELSE 0 END) +
(CASE WHEN (SELECT COUNT(*) FROM diary WHERE user_id=? AND CAST(strftime('%m', datum) AS INTEGER) IN (12,1,2)) >= 5 THEN 1 ELSE 0 END)
AS jahreszeiten_score
FROM (SELECT 1)
""", (user_id, user_id, user_id, user_id)).fetchone()
# Schnee: Diary-Einträge bei Schnee (weathercode 71-77)
schnee_row = conn.execute("""
SELECT COUNT(*) AS cnt FROM diary
WHERE user_id = ?
AND weather_json IS NOT NULL
AND CAST(json_extract(weather_json, '$.weathercode') AS INTEGER) BETWEEN 71 AND 77
""", (user_id,)).fetchone()
metrics = {
"total_km": stats["total_km"] if stats else 0,
"routen": stats["routen"] if stats else 0,
"pois": stats["pois"] if stats else 0,
"streak": (streak_row["current_streak"] if streak_row else 0),
"wiki_fotos": stats["wiki_fotos"] if stats else 0,
"total_km": stats["total_km"] if stats else 0,
"routen": stats["routen"] if stats else 0,
"pois": stats["pois"] if stats else 0,
"streak": (streak_row["current_streak"] if streak_row else 0),
"wiki_fotos": stats["wiki_fotos"] if stats else 0,
"wetter_tapfer_score": wetter_row["cnt"] if wetter_row else 0,
"jahreszeiten_score": (jahreszeiten_row["jahreszeiten_score"] if jahreszeiten_row else 0),
"schnee_eintraege": schnee_row["cnt"] if schnee_row else 0,
}
earned = {r["badge_id"] for r in
@ -211,6 +285,38 @@ async def my_achievements(user=Depends(get_current_user)):
"SELECT current_streak, max_streak FROM users WHERE id=?", (uid,)
).fetchone()
# Wetter-Tapferkeit
wetter_row = conn.execute("""
SELECT COUNT(*) AS cnt FROM diary d
LEFT JOIN diary_dogs dd ON dd.diary_id = d.id
WHERE d.user_id = ?
AND d.weather_json IS NOT NULL
AND (
CAST(json_extract(d.weather_json, '$.precip_prob') AS INTEGER) > 60
OR CAST(json_extract(d.weather_json, '$.temp_c') AS REAL) < 2
OR CAST(json_extract(d.weather_json, '$.wind_kmh') AS REAL) > 50
)
""", (uid,)).fetchone()
# Jahreszeiten
jahreszeiten_row = conn.execute("""
SELECT
(CASE WHEN (SELECT COUNT(*) FROM diary WHERE user_id=? AND CAST(strftime('%m', datum) AS INTEGER) IN (3,4,5)) >= 5 THEN 1 ELSE 0 END) +
(CASE WHEN (SELECT COUNT(*) FROM diary WHERE user_id=? AND CAST(strftime('%m', datum) AS INTEGER) IN (6,7,8)) >= 5 THEN 1 ELSE 0 END) +
(CASE WHEN (SELECT COUNT(*) FROM diary WHERE user_id=? AND CAST(strftime('%m', datum) AS INTEGER) IN (9,10,11)) >= 5 THEN 1 ELSE 0 END) +
(CASE WHEN (SELECT COUNT(*) FROM diary WHERE user_id=? AND CAST(strftime('%m', datum) AS INTEGER) IN (12,1,2)) >= 5 THEN 1 ELSE 0 END)
AS jahreszeiten_score
FROM (SELECT 1)
""", (uid, uid, uid, uid)).fetchone()
# Schnee-Einträge
schnee_row = conn.execute("""
SELECT COUNT(*) AS cnt FROM diary
WHERE user_id = ?
AND weather_json IS NOT NULL
AND CAST(json_extract(weather_json, '$.weathercode') AS INTEGER) BETWEEN 71 AND 77
""", (uid,)).fetchone()
earned_rows = conn.execute(
"SELECT badge_id FROM user_badges WHERE user_id=?", (uid,)
).fetchall()
@ -230,11 +336,14 @@ async def my_achievements(user=Depends(get_current_user)):
""", (stats["punkte"] if stats else 0,)).fetchone()
metrics = {
"total_km": stats["total_km"] if stats else 0,
"routen": stats["routen"] if stats else 0,
"pois": stats["pois"] if stats else 0,
"streak": (streak_row["current_streak"] if streak_row else 0),
"wiki_fotos": stats["wiki_fotos"] if stats else 0,
"total_km": stats["total_km"] if stats else 0,
"routen": stats["routen"] if stats else 0,
"pois": stats["pois"] if stats else 0,
"streak": (streak_row["current_streak"] if streak_row else 0),
"wiki_fotos": stats["wiki_fotos"] if stats else 0,
"wetter_tapfer_score": wetter_row["cnt"] if wetter_row else 0,
"jahreszeiten_score": (jahreszeiten_row["jahreszeiten_score"] if jahreszeiten_row else 0),
"schnee_eintraege": schnee_row["cnt"] if schnee_row else 0,
}
# Kategorien mit aktuellem Tier + Fortschritt aufbauen