banyaro/backend/routes/weather.py
rene 55069d246b Feature: Welten-Onboarding, Wetter-Motivation, UX-Fixes (SW by-v715)
Welten (worlds.js):
- Swipe-Hints beim ersten Öffnen (JETZT ← → WELT animiert, einmalig)
- Kein-Hund-Onboarding: Feature-Preview-Grid statt leerer Karte
- Hintergrund-Foto-Hint: Kamera-Karte wenn noch kein Tagebuchfoto
- worlds-back: navigiert zu Welcome wenn kein User eingeloggt
- Nach Logout: worlds-back Button sofort ausgeblendet

Wetter (wetter.js):
- Standort-Fehlerseite zu Motivations-Seite umgebaut
- Feature-Preview: Gassi-Score, 7-Tage, Regenradar, Rekorde
- CTA: Standort freigeben + Registrieren (nur für Gäste)

Settings (settings.js):
- Logo in Auth-Form: display:block + margin:0 auto zentriert
- Header bleibt sichtbar (FAB/Zurück-Navigation funktioniert)

Jobs (jobs.js):
- 2-Spalten-Grid auf Mobile: auto-fit statt festes 1fr 1fr
- Kein doppeltes Padding im Wrapper

Backend:
- weather.py, achievements.py: diary JOIN fix (d.user_id → dogs JOIN)
- Neue Wetter-Badges: wetter_tapfer, jahreszeiten, schnee
- Ernährungs-, Reise-, Ausgaben-Seite: diverse UX-Verbesserungen
- Presse-Seite erweitert
- Ban Yaro Foto-Assets (WebP + HIRES JPG)
2026-05-05 17:32:03 +02:00

90 lines
2.7 KiB
Python

"""
BAN YARO — Wetter-API
GET /api/weather?lat=&lon= → aktuelles Wetter + Zecken-Warnung für Nutzerstandort
"""
import json
from fastapi import APIRouter, Query, HTTPException, Depends
import weather as weather_module
from auth import get_current_user
from database import db
router = APIRouter()
@router.get('')
async def get_weather(
lat: float = Query(..., ge=-90, le=90),
lon: float = Query(..., ge=-180, le=180),
):
try:
return await weather_module.get_weather_for_location(lat, lon)
except Exception as exc:
raise HTTPException(503, f'Wetter nicht verfügbar: {exc}')
@router.get('/forecast')
async def get_weather_forecast(
lat: float = Query(..., ge=-90, le=90),
lon: float = Query(..., ge=-180, le=180),
user=Depends(get_current_user),
):
try:
return await weather_module.get_forecast(lat, lon)
except Exception as exc:
raise HTTPException(503, f'Wettervorhersage nicht verfügbar: {exc}')
@router.get('/records')
async def weather_records(user=Depends(get_current_user)):
"""Persönliche Wetterrekorde aus diary-Einträgen mit weather_json."""
uid = user["id"]
with db() as conn:
rows = conn.execute("""
SELECT d.datum, d.weather_json, d.titel
FROM diary d
JOIN dogs dog ON dog.id = d.dog_id
WHERE dog.user_id = ? AND d.weather_json IS NOT NULL
ORDER BY d.datum ASC
""", (uid,)).fetchall()
if not rows:
return {"records": None}
entries = []
for r in rows:
try:
w = json.loads(r["weather_json"])
entries.append({
"datum": r["datum"],
"titel": r["titel"],
"temp_c": w.get("temp_c"),
"wind_kmh": w.get("wind_kmh"),
"precip_prob": w.get("precip_prob"),
"desc": w.get("desc", ""),
"weathercode": w.get("weathercode"),
})
except Exception:
pass
if not entries:
return {"records": None}
temps = [e for e in entries if e["temp_c"] is not None]
winds = [e for e in entries if e["wind_kmh"] is not None]
records = {}
if temps:
kaeltester = min(temps, key=lambda e: e["temp_c"])
heissester = max(temps, key=lambda e: e["temp_c"])
records["kaeltester"] = kaeltester
records["heissester"] = heissester
if winds:
stuermischster = max(winds, key=lambda e: e["wind_kmh"])
records["stuermischster"] = stuermischster
regen_count = sum(1 for e in entries if (e.get("precip_prob") or 0) > 60)
records["regen_eintraege"] = regen_count
records["gesamt_eintraege"] = len(entries)
return {"records": records}