diff --git a/config.json b/config.json index 4bd7233..908806c 100644 --- a/config.json +++ b/config.json @@ -1,6 +1,6 @@ { "id": "chatelet", - "version": "0.3.0", + "version": "0.2.0", "name": "Chatelet", "repo": "https://git.atitlan.io/aiolabs/chatelet", "short_description": "Nostr-native room rentals (Airbnb-style) for LNbits", diff --git a/models.py b/models.py index 6fd20a8..8a239e3 100644 --- a/models.py +++ b/models.py @@ -17,7 +17,6 @@ Design notes carried into the field definitions: arbiter of "is this range open" — Nostr events are requests, not locks. """ -import json from datetime import datetime, timezone from enum import Enum @@ -195,17 +194,6 @@ class Block(BaseModel): # --------------------------------------------------------------------------- -def public_room_dict(room: Room) -> dict: - """A Room as public JSON for guests — strips operator-private fields: the - wallet id, and the check-in instructions (address/gate code, delivered only - in the encrypted post-payment DM). Shared by the HTTP and Nostr-RPC guest - doors so neither can leak them.""" - d = json.loads(room.json()) - d.pop("wallet", None) - d.pop("checkin_instructions", None) - return d - - class AvailabilityQuery(BaseModel): room_id: str check_in: str # YYYY-MM-DD inclusive diff --git a/tests/test_public_endpoints.py b/tests/test_public_endpoints.py deleted file mode 100644 index 363ae7c..0000000 --- a/tests/test_public_endpoints.py +++ /dev/null @@ -1,60 +0,0 @@ -"""Public guest discovery endpoints + the operator-private field strip -(privacy: check-in instructions must never reach a guest).""" - -import asyncio - -import pytest -from fastapi import HTTPException - -from .. import crud, views_api -from ..models import RoomStatus, public_room_dict -from .conftest import make_room - - -def test_public_room_dict_strips_private_fields(): - room = make_room(wallet="w1") - room.checkin_instructions = "gate code 4213, door on the left" - d = public_room_dict(room) - assert "wallet" not in d # operator-internal - assert "checkin_instructions" not in d # private, DM-only - assert d["title"] == "Tower Room" # public fields survive - assert d["price_amount"] == 100 - - -def test_public_rooms_lists_active_only_and_stripped(monkeypatch): - active = make_room("a", status=RoomStatus.active) - active.checkin_instructions = "secret" - inactive = make_room("b", status=RoomStatus.inactive) - - async def gr(): - return [active, inactive] - - monkeypatch.setattr(crud, "get_rooms", gr) - 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] - - -def test_public_room_404_when_inactive(monkeypatch): - async def gr(_): - return make_room(status=RoomStatus.inactive) - - monkeypatch.setattr(crud, "get_room", gr) - with pytest.raises(HTTPException) as e: - asyncio.run(views_api.api_public_room("x")) - assert e.value.status_code == 404 - - -def test_public_room_returns_stripped_when_active(monkeypatch): - room = make_room("a", status=RoomStatus.active) - room.checkin_instructions = "gate" - - async def gr(_): - return room - - monkeypatch.setattr(crud, "get_room", gr) - out = asyncio.run(views_api.api_public_room("a")) - assert out["id"] == "a" - assert "checkin_instructions" not in out - assert "wallet" not in out diff --git a/transport_rpcs.py b/transport_rpcs.py index d3e5cc3..f8f634b 100644 --- a/transport_rpcs.py +++ b/transport_rpcs.py @@ -196,9 +196,6 @@ def _to_dict(obj) -> dict: def _public_room(room) -> dict: - # Shared with the HTTP door; strips wallet id AND checkin_instructions - # (the latter was leaking to guests before — added after this file's - # original public dict). - from .models import public_room_dict - - return public_room_dict(room) + d = _to_dict(room) + d.pop("wallet", None) # wallet id is operator-internal, not for guests + return d diff --git a/views_api.py b/views_api.py index 7b28cde..1f24a87 100644 --- a/views_api.py +++ b/views_api.py @@ -24,7 +24,6 @@ from .models import ( CreateRoomData, Room, RoomStatus, - public_room_dict, ) from .nostr import service as nostr @@ -190,27 +189,6 @@ async def api_update_settings( return await crud.update_settings(settings) -# --- 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 - ] - - -@chatelet_api_router.get("/api/v1/public/rooms/{room_id}") -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) - - # --- availability (public read) --------------------------------------------