feat: per-operator settings — house rules + card acceptance (multi-tenant)
Chatelet is multi-tenant: any LNbits user can host rooms. What an operator decides for all their rooms now lives in chatelet.operator_settings, keyed by user id and created lazily (m003, which also indexes bookings by guest): check-in/out times, cancellation policy, and accept_fiat. Guests see it: the public room view (both doors) gains house_rules and payment_methods, and the kind:30402 listing carries payment_methods, checkin_time and checkout_time tags so a generic Nostr client can render the right pay buttons and rules without our RPC. The check-in DM reads the room owner's rules instead of the instance row. Card is offered only when the operator opted in, the room is fiat-priced, and LNbits core has a fiat provider for that user — resolved through settings.get_fiat_providers_for_user(owner), the one seam lnbits#67's per-user Stripe credentials will plug into; chatelet never sees creds. Operator endpoints: GET/PUT /api/v1/operator (admin key → wallet user) and RPC twins chatelet_operator_get/update (AUTH_WALLET); saving re-publishes the owner's active listings. Admin UI moves the house-rule inputs into a per-operator card with the card toggle and a provider hint. The old house-rule columns on settings stay for old rows but are no longer read. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
parent
feaaef93e3
commit
9ab52f2c69
17 changed files with 531 additions and 42 deletions
51
views_api.py
51
views_api.py
|
|
@ -22,11 +22,12 @@ from .models import (
|
|||
ChateletSettings,
|
||||
CreateBlockData,
|
||||
CreateRoomData,
|
||||
OperatorSettings,
|
||||
Room,
|
||||
RoomStatus,
|
||||
UnavailableRanges,
|
||||
UpdateOperatorSettings,
|
||||
public_booking_dict,
|
||||
public_room_dict,
|
||||
)
|
||||
from .nostr import service as nostr
|
||||
|
||||
|
|
@ -192,17 +193,51 @@ async def api_update_settings(
|
|||
return await crud.update_settings(settings)
|
||||
|
||||
|
||||
# --- operator settings (per LNbits user; admin key → wallet → user) ----------
|
||||
|
||||
|
||||
def _with_providers(ops: OperatorSettings) -> dict:
|
||||
"""The row plus what core would actually let this user charge with, so
|
||||
the admin UI can explain a card toggle that has no provider behind it."""
|
||||
d = ops.dict()
|
||||
d["available_fiat_providers"] = services.fiat_providers_for_user(ops.user_id)
|
||||
return d
|
||||
|
||||
|
||||
@chatelet_api_router.get("/api/v1/operator")
|
||||
async def api_get_operator_settings(
|
||||
key: WalletTypeInfo = Depends(require_admin_key),
|
||||
) -> dict:
|
||||
ops = await crud.get_or_create_operator_settings(key.wallet.user)
|
||||
return _with_providers(ops)
|
||||
|
||||
|
||||
@chatelet_api_router.put("/api/v1/operator")
|
||||
async def api_update_operator_settings(
|
||||
data: UpdateOperatorSettings, key: WalletTypeInfo = Depends(require_admin_key)
|
||||
) -> dict:
|
||||
ops = await crud.get_or_create_operator_settings(key.wallet.user)
|
||||
for field in UpdateOperatorSettings.__fields__:
|
||||
setattr(ops, field, getattr(data, field))
|
||||
ops = await crud.update_operator_settings(ops)
|
||||
# Rails/house rules ride on the public listing — refresh the owner's rooms.
|
||||
for room in await crud.get_rooms():
|
||||
if room.status == RoomStatus.active:
|
||||
owner = await services.room_owner_id(room)
|
||||
if owner == ops.user_id:
|
||||
await nostr.publish_listing(room)
|
||||
return _with_providers(ops)
|
||||
|
||||
|
||||
# --- public guest discovery (no auth) --------------------------------------
|
||||
|
||||
|
||||
@chatelet_api_router.get("/api/v1/public/rooms")
|
||||
async def api_public_rooms() -> list[dict]:
|
||||
"""Active rooms for guest browsing — operator-private fields stripped."""
|
||||
return [
|
||||
public_room_dict(r)
|
||||
for r in await crud.get_rooms()
|
||||
if r.status == RoomStatus.active
|
||||
]
|
||||
"""Active rooms for guests — wallet + check-in instructions stripped,
|
||||
owner's house rules + accepted rails attached."""
|
||||
rooms = [r for r in await crud.get_rooms() if r.status == RoomStatus.active]
|
||||
return await services.public_room_views(rooms)
|
||||
|
||||
|
||||
@chatelet_api_router.get("/api/v1/public/rooms/{room_id}")
|
||||
|
|
@ -210,7 +245,7 @@ async def api_public_room(room_id: str) -> dict:
|
|||
room = await crud.get_room(room_id)
|
||||
if not room or room.status != RoomStatus.active:
|
||||
raise HTTPException(404, "Room not available")
|
||||
return public_room_dict(room)
|
||||
return await services.public_room_view(room)
|
||||
|
||||
|
||||
@chatelet_api_router.get("/api/v1/public/rooms/{room_id}/unavailable")
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue