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
|
|
@ -2,6 +2,7 @@
|
|||
(privacy: check-in instructions must never reach a guest)."""
|
||||
|
||||
import asyncio
|
||||
from typing import Any
|
||||
|
||||
import pytest
|
||||
from fastapi import HTTPException
|
||||
|
|
@ -14,7 +15,7 @@ from ..models import (
|
|||
public_booking_dict,
|
||||
public_room_dict,
|
||||
)
|
||||
from .conftest import make_room
|
||||
from .conftest import make_room, patch_owner
|
||||
|
||||
|
||||
def test_public_room_dict_strips_private_fields():
|
||||
|
|
@ -36,10 +37,13 @@ def test_public_rooms_lists_active_only_and_stripped(monkeypatch):
|
|||
return [active, inactive]
|
||||
|
||||
monkeypatch.setattr(crud, "get_rooms", gr)
|
||||
patch_owner(monkeypatch)
|
||||
out = asyncio.run(views_api.api_public_rooms())
|
||||
assert [r["id"] for r in out] == ["a"] # inactive hidden from guests
|
||||
assert "checkin_instructions" not in out[0]
|
||||
assert "wallet" not in out[0]
|
||||
assert out[0]["house_rules"]["checkin_time"] == "15:00"
|
||||
assert out[0]["payment_methods"] == ["lightning"]
|
||||
|
||||
|
||||
def test_public_room_404_when_inactive(monkeypatch):
|
||||
|
|
@ -60,14 +64,15 @@ def test_public_room_returns_stripped_when_active(monkeypatch):
|
|||
return room
|
||||
|
||||
monkeypatch.setattr(crud, "get_room", gr)
|
||||
patch_owner(monkeypatch)
|
||||
out = asyncio.run(views_api.api_public_room("a"))
|
||||
assert out["id"] == "a"
|
||||
assert "checkin_instructions" not in out
|
||||
assert "wallet" not in out
|
||||
|
||||
|
||||
def _booking(**overrides) -> Booking:
|
||||
base = {
|
||||
def _booking(**overrides: Any) -> Booking:
|
||||
base: dict[str, Any] = {
|
||||
"id": "bk_1234567",
|
||||
"room_id": "a",
|
||||
"guest_pubkey": "ab" * 32,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue