diff --git a/gateway/platforms/matrix.py b/gateway/platforms/matrix.py index 4aebd92b15..021a453040 100644 --- a/gateway/platforms/matrix.py +++ b/gateway/platforms/matrix.py @@ -1598,11 +1598,21 @@ class MatrixAdapter(BasePlatformAdapter): if not self._client: return False try: - await self._client.set_read_markers( - RoomID(room_id), - fully_read_event=EventID(event_id), - read_receipt=EventID(event_id), - ) + room = RoomID(room_id) + event = EventID(event_id) + if hasattr(self._client, "set_fully_read_marker"): + await self._client.set_fully_read_marker(room, event, event) + elif hasattr(self._client, "send_receipt"): + await self._client.send_receipt(room, event) + elif hasattr(self._client, "set_read_markers"): + await self._client.set_read_markers( + room, + fully_read_event=event, + read_receipt=event, + ) + else: + logger.debug("Matrix: client has no read receipt method") + return False logger.debug("Matrix: sent read receipt for %s in %s", event_id, room_id) return True except Exception as exc: diff --git a/scripts/release.py b/scripts/release.py index 384f2f65e4..5b3949763d 100755 --- a/scripts/release.py +++ b/scripts/release.py @@ -69,6 +69,7 @@ AUTHOR_MAP = { "241404605+MestreY0d4-Uninter@users.noreply.github.com": "MestreY0d4-Uninter", "109555139+davetist@users.noreply.github.com": "davetist", # contributors (manual mapping from git names) + "ahmedsherif95@gmail.com": "asheriif", "dmayhem93@gmail.com": "dmahan93", "samherring99@gmail.com": "samherring99", "desaiaum08@gmail.com": "Aum08Desai", diff --git a/tests/gateway/test_matrix.py b/tests/gateway/test_matrix.py index 90d8200469..19ed200b06 100644 --- a/tests/gateway/test_matrix.py +++ b/tests/gateway/test_matrix.py @@ -1740,16 +1740,49 @@ class TestMatrixReadReceipts: def setup_method(self): self.adapter = _make_adapter() + @pytest.mark.asyncio + async def test_accepted_message_schedules_read_receipt(self): + self.adapter._is_dm_room = AsyncMock(return_value=True) + self.adapter._get_display_name = AsyncMock(return_value="Alice") + self.adapter._background_read_receipt = MagicMock() + + ctx = await self.adapter._resolve_message_context( + room_id="!room:ex", + sender="@alice:ex", + event_id="$event1", + body="hello", + source_content={"body": "hello"}, + relates_to={}, + ) + + assert ctx is not None + self.adapter._background_read_receipt.assert_called_once_with( + "!room:ex", "$event1" + ) + @pytest.mark.asyncio async def test_send_read_receipt(self): - """send_read_receipt should call client.set_read_markers.""" + """send_read_receipt should call mautrix's real read-marker API.""" mock_client = MagicMock() - mock_client.set_read_markers = AsyncMock(return_value=None) + mock_client.set_fully_read_marker = AsyncMock(return_value=None) self.adapter._client = mock_client result = await self.adapter.send_read_receipt("!room:ex", "$event1") assert result is True - mock_client.set_read_markers.assert_called_once() + mock_client.set_fully_read_marker.assert_awaited_once_with( + "!room:ex", "$event1", "$event1" + ) + + @pytest.mark.asyncio + async def test_send_read_receipt_falls_back_to_receipt_only(self): + """send_read_receipt should still work with clients lacking read markers.""" + mock_client = MagicMock(spec=["send_receipt"]) + mock_client.send_receipt = AsyncMock(return_value=None) + self.adapter._client = mock_client + + result = await self.adapter.send_read_receipt("!room:ex", "$event1") + assert result is True + mock_client.send_receipt.assert_awaited_once_with("!room:ex", "$event1") @pytest.mark.asyncio async def test_read_receipt_no_client(self): @@ -1852,5 +1885,3 @@ class TestMatrixPresence: self.adapter._client = None result = await self.adapter.set_presence("online") assert result is False - -