feat(api): keyless GET /api/v1/public/bookings/{id} for guests
The guest cannot subscribe to the operator's wallet and the existing booking read needs a wallet invoice key, so a client had no way to wait for awaiting_payment -> confirmed over HTTP short of polling the invoice on LNbits core. Add the HTTP twin of the RPC door's chatelet_booking_get: the 10-char booking id from the quote is the capability, and the response is public_booking_dict — lifecycle, dates and money only, with the guest's pubkey/contact and the Lightning/Nostr plumbing stripped. Closes #18 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
parent
d521782f19
commit
94542ad0f9
4 changed files with 106 additions and 2 deletions
|
|
@ -7,7 +7,13 @@ import pytest
|
|||
from fastapi import HTTPException
|
||||
|
||||
from .. import crud, views_api
|
||||
from ..models import RoomStatus, public_room_dict
|
||||
from ..models import (
|
||||
Booking,
|
||||
BookingStatus,
|
||||
RoomStatus,
|
||||
public_booking_dict,
|
||||
public_room_dict,
|
||||
)
|
||||
from .conftest import make_room
|
||||
|
||||
|
||||
|
|
@ -58,3 +64,66 @@ def test_public_room_returns_stripped_when_active(monkeypatch):
|
|||
assert out["id"] == "a"
|
||||
assert "checkin_instructions" not in out
|
||||
assert "wallet" not in out
|
||||
|
||||
|
||||
def _booking(**overrides) -> Booking:
|
||||
base = {
|
||||
"id": "bk_1234567",
|
||||
"room_id": "a",
|
||||
"guest_pubkey": "ab" * 32,
|
||||
"guest_contact": "guest@example.com",
|
||||
"check_in": "2026-10-05",
|
||||
"check_out": "2026-10-07",
|
||||
"nights": 2,
|
||||
"num_guests": 1,
|
||||
"currency": "EUR",
|
||||
"price_fiat": 200.0,
|
||||
"amount_sat": 300000,
|
||||
"deposit_sat": 300000,
|
||||
"status": BookingStatus.awaiting_payment,
|
||||
"payment_hash": "ph_1",
|
||||
"request_event_id": "req_ev",
|
||||
"reservation_event_id": "res_ev",
|
||||
}
|
||||
base.update(overrides)
|
||||
return Booking(**base)
|
||||
|
||||
|
||||
def test_public_booking_dict_strips_identity_and_plumbing():
|
||||
d = public_booking_dict(_booking())
|
||||
for private in (
|
||||
"guest_pubkey",
|
||||
"guest_contact",
|
||||
"payment_hash",
|
||||
"request_event_id",
|
||||
"reservation_event_id",
|
||||
):
|
||||
assert private not in d
|
||||
# What a guest client needs to render "waiting" / "booked" / "expired".
|
||||
assert d["id"] == "bk_1234567"
|
||||
assert d["status"] == "awaiting_payment"
|
||||
assert d["check_in"] == "2026-10-05"
|
||||
assert d["nights"] == 2
|
||||
assert d["deposit_sat"] == 300000
|
||||
assert "expires_at" in d
|
||||
|
||||
|
||||
def test_public_booking_404_when_missing(monkeypatch):
|
||||
async def gb(_):
|
||||
return None
|
||||
|
||||
monkeypatch.setattr(crud, "get_booking", gb)
|
||||
with pytest.raises(HTTPException) as e:
|
||||
asyncio.run(views_api.api_public_booking("nope"))
|
||||
assert e.value.status_code == 404
|
||||
|
||||
|
||||
def test_public_booking_returns_stripped(monkeypatch):
|
||||
async def gb(_):
|
||||
return _booking(status=BookingStatus.confirmed)
|
||||
|
||||
monkeypatch.setattr(crud, "get_booking", gb)
|
||||
out = asyncio.run(views_api.api_public_booking("bk_1234567"))
|
||||
assert out["status"] == "confirmed"
|
||||
assert "guest_contact" not in out
|
||||
assert "payment_hash" not in out
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue