Fix remote portal trip list

- /api/trips now returns {trips:[...]} to match what history.js expects (result.trips)
- odo_start_km null guard in history.js (server trips have no odometer data)
- require_login returns 401 JSON for /api/* paths instead of HTML redirect

Co-authored-by: Copilot <[email protected]>
This commit is contained in:
Mathieu Moran
2026-08-10 04:27:57 -04:00
co-authored by Copilot
parent 64b9481ce0
commit 693848aba1
3 changed files with 13 additions and 4 deletions
+7 -2
View File
@@ -562,8 +562,13 @@ def recompute_trips():
@app.get("/api/trips")
@require_login
def portal_trips_compat():
"""Pi history.js compatibility alias."""
return portal_trips()
"""Pi history.js compatibility alias — wraps response in {trips: [...]}."""
device_id = _portal_device_id()
if device_id is None:
return jsonify(error="device not configured"), 404
limit = min(int(request.args.get("limit", 200)), 1000)
trips = db.list_trips(device_id, limit=limit)
return jsonify(trips=trips)
@app.get("/api/trip/<int:trip_id>")
+5 -1
View File
@@ -38,10 +38,14 @@ def hash_password(plain):
def require_login(view):
"""Decorator: redirect to login page if not authenticated."""
"""Decorator: redirect to login page if not authenticated (HTML routes),
or return 401 JSON for /api/* routes."""
@wraps(view)
def wrapped(*args, **kwargs):
if not current_user.is_authenticated:
from flask import request, jsonify
if request.path.startswith("/api/"):
return jsonify(error="not authenticated"), 401
return redirect(url_for("login_page"))
return view(*args, **kwargs)
return wrapped
+1 -1
View File
@@ -189,7 +189,7 @@
<td>${formatDistance(trip.distance_km)}</td>
<td>${formatDuration(trip.duration_seconds)}</td>
<td>${formatSpeed(trip.max_speed_kmh)}</td>
<td class="text-muted small">${trip.odo_start_km.toFixed(0)} → ${trip.odo_end_km.toFixed(0)} km</td>
<td class="text-muted small">${trip.odo_start_km != null ? trip.odo_start_km.toFixed(0) + ' → ' + trip.odo_end_km.toFixed(0) + ' km' : '—'}</td>
<td class="text-end d-none d-sm-table-cell">
<button class="btn btn-sm btn-primary" type="button" data-trip-id="${trip.id}">
Replay