Public booking page + iframe embed (#17)
Adds the customer-facing /book/<slug> page: service/slot picker, booking form, and confirmation screen, built on #16's existing booking JSON API. Includes iframe auto-fit height reporting (mirroring deploy/booking/booking_layout.js's eaBookingHeight message), brand-color theming via a ?color= query param, a honeypot field with a fake-success response indistinguishable from a real booking, and a clear "just taken" message on slot-conflict. Caddy per-IP rate limiting is documented in deploy/booking/RATE_LIMIT.md for manual application (no Caddyfile is tracked in this repo). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -117,6 +117,19 @@ def slots():
|
||||
@bp.post("")
|
||||
def create_booking():
|
||||
body = request.get_json(force=True, silent=True) or {}
|
||||
if (body.get("website") or "").strip():
|
||||
# Honeypot field: real customers never see or fill it (hidden from
|
||||
# sighted users and screen readers alike), so a filled value means a
|
||||
# scripted bot filled every field it could find. Fake a normal-looking
|
||||
# success instead of a 4xx so a scripted client has no signal it was
|
||||
# caught -- no booking is created, but the id/token are shaped exactly
|
||||
# like a real create_booking() response (same id format, same client_id
|
||||
# in the token's claims) so nothing about this response is
|
||||
# distinguishable from a genuine one by a client inspecting it.
|
||||
fake_booking_id = bdb.new_id("BK")
|
||||
return jsonify({"booking_id": fake_booking_id, "status": "confirmed",
|
||||
"token": _mint_manage_token(body.get("client_id") or "",
|
||||
fake_booking_id)}), 201
|
||||
client_id = body.get("client_id")
|
||||
resource_id = body.get("resource_id")
|
||||
service_id = body.get("service_id")
|
||||
|
||||
Reference in New Issue
Block a user