Feature: Ratings, Lightbox, Forum-Standort, Notifications, Routen-Recording, Chat-Picker

- Bewertungssystem (ratings.py): Sterne für Sitter/Walks/Places/Routen
- Admin: Server-Log-Viewer + OSM-Cache-Statistiken
- Chat: "Neue Nachricht"-Button mit Freundesliste-Picker
- Forum: 5 neue Kategorien, Standorteingabe (locationPicker), Absende-Toast, Lightbox
- Freunde: Aktivitäts-Filter (Chips), Freundschaftsanfrage → In-App-Notification
- Sitter: locationPicker statt manuelle Koordinateneingabe + ratingStars
- Tagebuch: Bilder-Lightbox im Detail-View, iOS-Modal-Header-Fix (90svh)
- Routen: Start/Stopp-Button wechselt Zustand, nutzt Page_map.isRecording()
- Benachrichtigungen: Delete-Button sichtbar, typ-basierte Navigation, Toast-Feedback
- OSM: globales Semaphore + 429-Retry-Logic; Scheduler: München-Umland, täglich
- SW by-v225, APP_VER 202
This commit is contained in:
rene 2026-04-19 09:40:35 +02:00
parent aa70a838f2
commit e56183b642
21 changed files with 648 additions and 175 deletions

View file

@ -96,7 +96,7 @@ async def search_users(q: str = "", user=Depends(get_current_user)):
FROM dogs d WHERE d.user_id=u.id AND d.is_public=1) AS dogs_json
FROM users u
WHERE u.id != ?
AND u.name LIKE ?
AND norm(u.name) LIKE norm(?)
AND NOT EXISTS (
SELECT 1 FROM friendships f
WHERE (f.requester_id=? AND f.addressee_id=u.id)
@ -142,6 +142,19 @@ async def send_request(target_id: int, user=Depends(get_current_user)):
(uid, target_id)
)
# In-App Benachrichtigung + Badge
try:
with db() as conn:
conn.execute(
"""INSERT INTO notifications (user_id, type, title, body, data)
VALUES (?, 'friend_request', 'Neue Freundschaftsanfrage', ?, ?)""",
(target_id,
f"{user['name']} möchte dein Freund sein.",
'{"page":"friends"}')
)
except Exception:
pass
try:
from routes.push import send_push_to_user
send_push_to_user(target_id, {
@ -223,7 +236,7 @@ async def get_activity(user=Depends(get_current_user)):
JOIN users u ON u.id = d.user_id
WHERE d.user_id IN ({ph})
ORDER BY dg.created_at DESC
LIMIT 30
LIMIT 15
""", friend_ids).fetchall()
# Gesundheitseinträge der Freunde (nur Typ + Datum, kein Inhalt)
@ -241,7 +254,7 @@ async def get_activity(user=Depends(get_current_user)):
JOIN users u ON u.id = d.user_id
WHERE d.user_id IN ({ph})
ORDER BY h.created_at DESC
LIMIT 30
LIMIT 15
""", friend_ids).fetchall()
# Gassi-Treffen der Freunde
@ -259,7 +272,7 @@ async def get_activity(user=Depends(get_current_user)):
JOIN users u ON u.id = w.user_id
WHERE w.user_id IN ({ph})
ORDER BY w.created_at DESC
LIMIT 30
LIMIT 15
""", friend_ids).fetchall()
# Neue Hunde (angelegt in den letzten 30 Tagen)
@ -277,7 +290,7 @@ async def get_activity(user=Depends(get_current_user)):
WHERE d.user_id IN ({ph})
AND d.created_at >= datetime('now', '-30 days')
ORDER BY d.created_at DESC
LIMIT 30
LIMIT 15
""", friend_ids).fetchall()
_ICON = {
@ -309,7 +322,7 @@ async def get_activity(user=Depends(get_current_user)):
# Zusammenführen und nach created_at absteigend sortieren, max. 30
items.sort(key=lambda x: x["created_at"] or "", reverse=True)
return items[:30]
return items[:50]
@router.delete("/{friend_user_id}")