fix(api): parse form-urlencoded POST body in fleet-dashboard handler
The Fleet Trips SPA posts application/x-www-form-urlencoded, but the
POST /webhook/fleet-dashboard handler read the body with request.json().
That threw on every request, the except swallowed it to body={}, and all
filters (vehicle_numbers, cost_centre, assigned_city) plus period/dates
were dropped — so every query returned the full unfiltered fleet (1,266
trips) regardless of the dropdowns. The map/KPIs/trips never changed,
which read as "the dropdowns don't work."
Parse by Content-Type: urllib.parse.parse_qs for form bodies (no new
dependency — avoids python-multipart), JSON still accepted defensively
for n8n-compat callers.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
26fa1a4dc5
commit
f1387d1476
1 changed files with 16 additions and 4 deletions
|
|
@ -31,9 +31,11 @@ is the base URL (the `N8N_BASE` constant in each dashboard SPA):
|
|||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import os
|
||||
from contextlib import asynccontextmanager
|
||||
from datetime import date, datetime, timedelta, timezone
|
||||
from urllib.parse import parse_qs
|
||||
|
||||
import psycopg2.extras
|
||||
from fastapi import FastAPI, Request
|
||||
|
|
@ -202,13 +204,23 @@ def _preset_to_range(period: str | None, start_date, end_date):
|
|||
|
||||
@app.post("/webhook/fleet-dashboard")
|
||||
async def fleet_trips(request: Request):
|
||||
# The dashboard SPA posts application/x-www-form-urlencoded (not JSON), so
|
||||
# parse by content-type. Reading the raw body + parse_qs avoids pulling in
|
||||
# python-multipart. JSON is still accepted defensively (n8n-compat callers).
|
||||
body: dict = {}
|
||||
ctype = request.headers.get("content-type", "").lower()
|
||||
try:
|
||||
body = await request.json()
|
||||
raw = await request.body()
|
||||
if "application/json" in ctype:
|
||||
parsed = json.loads(raw or b"{}")
|
||||
body = parsed if isinstance(parsed, dict) else {}
|
||||
else:
|
||||
# x-www-form-urlencoded — parse_qs yields lists; keep the last value.
|
||||
body = {k: v[-1] for k, v in parse_qs(raw.decode("utf-8", "replace")).items()}
|
||||
except Exception:
|
||||
body = {}
|
||||
if not isinstance(body, dict):
|
||||
body = {}
|
||||
body = body.get("body", body) if isinstance(body.get("body"), dict) else body
|
||||
if isinstance(body.get("body"), dict):
|
||||
body = body["body"]
|
||||
|
||||
start, end = _preset_to_range(
|
||||
body.get("period"), body.get("start_date"), body.get("end_date")
|
||||
|
|
|
|||
Loading…
Reference in a new issue