Private
Public Access
Fix DM recipient never seeing the new conversation (#52 follow-up)
start_dm_endpoint created the room and membership correctly but never sent the room_added signal every other "you're now in a room" path (add_member) already sends -- without it, GET /rooms/mine is only fetched once at app mount, so a DM started against an already-open client stayed completely invisible until a manual reload. The recipient still got an offline push/desktop notification (that path is independent, via _notify_offline_members), just nothing to actually open when they went looking in an already-loaded session. Added a test mirroring the existing add_member broadcast test exactly (recipient connected but never joined any room channel, proving the signal alone is what tells their client the room exists) -- it failed before this fix and passes now. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -113,15 +113,23 @@ async def create_room_endpoint(
|
||||
@router.post("/dm", response_model=RoomRead, status_code=201)
|
||||
async def start_dm_endpoint(
|
||||
data: StartDmRequest,
|
||||
request: Request,
|
||||
current_user: User = Depends(get_current_user),
|
||||
db: AsyncSession = Depends(get_db),
|
||||
):
|
||||
try:
|
||||
return await find_or_create_dm(db, current_user.id, data.other_user_id)
|
||||
room = await find_or_create_dm(db, current_user.id, data.other_user_id)
|
||||
except CannotDmSelfError:
|
||||
raise HTTPException(status_code=400, detail="Cannot start a DM with yourself")
|
||||
except TargetUserNotFoundError:
|
||||
raise HTTPException(status_code=404, detail="No user with that ID")
|
||||
# Same signal add_member sends -- without it, the other participant's
|
||||
# already-open client has no way to know this DM exists until they
|
||||
# reload: GET /rooms/mine is only fetched once at app mount. Sent
|
||||
# unconditionally (not just on genuine creation) since re-finding an
|
||||
# existing DM and refreshing their room list again is harmless.
|
||||
await broadcast_room_added(request.app.state.broadcaster, data.other_user_id, room)
|
||||
return room
|
||||
|
||||
|
||||
@router.get("", response_model=list[RoomListItem])
|
||||
|
||||
@@ -146,6 +146,28 @@ def test_add_member_notifies_target_user_via_websocket(ws_client_factory, monkey
|
||||
assert received == {"type": "room_added", "room_id": room["id"]}
|
||||
|
||||
|
||||
def test_start_dm_notifies_other_participant_via_websocket(ws_client_factory):
|
||||
# A production report: bob had no idea a DM existed until he reloaded --
|
||||
# find_or_create_dm was creating the room/membership correctly but never
|
||||
# sending this signal, unlike every other "you're now in a room" path
|
||||
# (add_member, above). Same shape as that test: bob is only ever
|
||||
# "connected," never "joined," proving the signal alone is what tells
|
||||
# his client the room exists at all.
|
||||
instance1 = ws_client_factory()
|
||||
instance2 = ws_client_factory()
|
||||
|
||||
alice = _register_ws(instance1, _unique("alice"))
|
||||
bob = _register_ws(instance2, _unique("bob"))
|
||||
|
||||
with instance2.websocket_connect("/ws/chat") as bob_ws:
|
||||
resp = instance1.post("/api/rooms/dm", json={"other_user_id": bob["id"]})
|
||||
assert resp.status_code == 201, resp.text
|
||||
room = resp.json()
|
||||
|
||||
received = bob_ws.receive_json()
|
||||
assert received == {"type": "room_added", "room_id": room["id"]}
|
||||
|
||||
|
||||
def test_profile_update_notifies_room_members_via_websocket(ws_client_factory, monkeypatch):
|
||||
# Only reaches clients that have the room's own channel joined --
|
||||
# exactly the case where a stale avatar/display name would actually be
|
||||
|
||||
Reference in New Issue
Block a user