Rate-limit public bookings per contact; add direct owner contact endpoint
Test backoffice (smb-crm) / test (push) Successful in 1m43s
Test backoffice (smb-crm) / test (push) Successful in 1m43s
Public booking API now rejects a 6th active booking from the same customer_contact within 24h (429), stopping one contact from filling every slot on every resource, while owner-entered manual bookings stay unaffected. Add POST /api/contact: client sites can reach their own owner's inbox directly (via their existing login email) for general inquiries, separate from the agency's leads/Telegram pipeline (n8n/lead-intake.json), which stays reserved for actual prospects contacting the agency itself. Paris Barber Shop's contact form and Rückruf widget now point here; the Rückruf floating widget itself has been removed from the site. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -383,6 +383,22 @@ def list_active_bookings_for_resource(client_id, resource_id, start, end,
|
||||
return cur.fetchall()
|
||||
|
||||
|
||||
def count_recent_bookings_by_contact(client_id, customer_contact, since):
|
||||
"""Count of client_id's non-cancelled bookings for customer_contact
|
||||
created at or after `since` -- the public booking API's per-contact rate
|
||||
limit reads this to stop one contact from filling every slot on every
|
||||
resource. Owner-entered bookings (source="owner") count here too, since
|
||||
an owner double-booking themselves in isn't the scenario this guards
|
||||
against and excluding it would only add a footgun for no benefit."""
|
||||
with db.connect() as conn, conn.cursor() as cur:
|
||||
cur.execute(
|
||||
"SELECT count(*) AS n FROM bookings WHERE client_id = %s "
|
||||
"AND customer_contact = %s AND status != 'cancelled' "
|
||||
"AND created_at >= %s",
|
||||
(client_id, customer_contact, since))
|
||||
return cur.fetchone()["n"]
|
||||
|
||||
|
||||
def update_booking(client_id, booking_id, **fields):
|
||||
"""Update a booking scoped to client_id (e.g. reschedule/cancel).
|
||||
Returns the updated row, or None if no such booking exists for this
|
||||
|
||||
Reference in New Issue
Block a user