From b8299fa83d5098ed47e19115a6c417e9c9c00d62 Mon Sep 17 00:00:00 2001 From: Antoine Poindron Date: Sat, 9 May 2026 10:29:19 +0200 Subject: [PATCH 1/2] fix(client/requests): hide draft quotes from the client-facing detail page MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Drafts are caterer-only — they're work-in-progress quotes the caterer hasn't sent yet. Surfacing them on the client side leaks pricing + caterer identity before the caterer is ready to commit (and the client sees a "Brouillon" badge they shouldn't even know exists). Filter at the DB level — `select(Quote).where(Quote.status != QuoteStatus.draft)` — so the row never reaches a Jinja context. Templates aren't touched. The companion route `client.quote_pdf` (PR #44) gets the same filter in its own branch. Co-Authored-By: Claude Opus 4.7 (1M context) --- blueprints/client/requests.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/blueprints/client/requests.py b/blueprints/client/requests.py index 80c3417..258540d 100644 --- a/blueprints/client/requests.py +++ b/blueprints/client/requests.py @@ -403,10 +403,16 @@ def request_detail(request_id): .all() ) + # Drafts are caterer-only — they're work-in-progress quotes the + # caterer hasn't sent yet. Surfacing them on the client side + # leaks pricing + caterer identity before the caterer is ready + # to commit. Filter at the DB level (not in the template) so + # the row never reaches a Jinja context. quotes = ( db.execute( select(Quote) .where(Quote.quote_request_id == request_id) + .where(Quote.status != QuoteStatus.draft) .order_by(Quote.created_at.asc()) ) .scalars() From 10d6a976e07e7b52bae049691cbb3c60e6e9b224 Mon Sep 17 00:00:00 2001 From: scttpr Date: Sun, 10 May 2026 17:48:58 +0200 Subject: [PATCH 2/2] fix(client/requests): use _QUOTE_RECEIVED_STATUSES allow-list for draft filter --- blueprints/client/requests.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/blueprints/client/requests.py b/blueprints/client/requests.py index 258540d..4b6008c 100644 --- a/blueprints/client/requests.py +++ b/blueprints/client/requests.py @@ -406,13 +406,14 @@ def request_detail(request_id): # Drafts are caterer-only — they're work-in-progress quotes the # caterer hasn't sent yet. Surfacing them on the client side # leaks pricing + caterer identity before the caterer is ready - # to commit. Filter at the DB level (not in the template) so - # the row never reaches a Jinja context. + # to commit. Allow-list rather than `!= draft` so a future + # status doesn't leak by default — same gate as the dashboard + # helpers and the client.quote_pdf route. quotes = ( db.execute( select(Quote) .where(Quote.quote_request_id == request_id) - .where(Quote.status != QuoteStatus.draft) + .where(Quote.status.in_(_QUOTE_RECEIVED_STATUSES)) .order_by(Quote.created_at.asc()) ) .scalars()