From 2586d3cd0d0405d318cec4c403be955e7fb9402e Mon Sep 17 00:00:00 2001 From: Slipstream Date: Sun, 15 Jun 2025 18:49:48 -0600 Subject: [PATCH] Add message crosspost support (#104) --- disagreement/http.py | 21 ++++++++++++----- disagreement/models.py | 13 +++++++++-- tests/test_crosspost_message.py | 41 +++++++++++++++++++++++++++++++++ 3 files changed, 67 insertions(+), 8 deletions(-) create mode 100644 tests/test_crosspost_message.py diff --git a/disagreement/http.py b/disagreement/http.py index 4b7b46f..a2aaddd 100644 --- a/disagreement/http.py +++ b/disagreement/http.py @@ -656,12 +656,21 @@ class HTTPClient: await self.request("PUT", f"/channels/{channel_id}/pins/{message_id}") - async def unpin_message( - self, channel_id: "Snowflake", message_id: "Snowflake" - ) -> None: - """Unpins a message from a channel.""" - - await self.request("DELETE", f"/channels/{channel_id}/pins/{message_id}") + async def unpin_message( + self, channel_id: "Snowflake", message_id: "Snowflake" + ) -> None: + """Unpins a message from a channel.""" + + await self.request("DELETE", f"/channels/{channel_id}/pins/{message_id}") + + async def crosspost_message( + self, channel_id: "Snowflake", message_id: "Snowflake" + ) -> Dict[str, Any]: + """Crossposts a message to any following channels.""" + + return await self.request( + "POST", f"/channels/{channel_id}/messages/{message_id}/crosspost" + ) async def delete_channel( self, channel_id: str, reason: Optional[str] = None diff --git a/disagreement/models.py b/disagreement/models.py index fdd3f31..10d92c5 100644 --- a/disagreement/models.py +++ b/disagreement/models.py @@ -177,8 +177,17 @@ class Message: HTTPException Unpinning the message failed. """ - await self._client._http.unpin_message(self.channel_id, self.id) - self.pinned = False + await self._client._http.unpin_message(self.channel_id, self.id) + self.pinned = False + + async def crosspost(self) -> "Message": + """|coro| + + Crossposts this message to all follower channels and return the resulting message. + """ + + data = await self._client._http.crosspost_message(self.channel_id, self.id) + return self._client.parse_message(data) async def reply( self, diff --git a/tests/test_crosspost_message.py b/tests/test_crosspost_message.py new file mode 100644 index 0000000..cae1f32 --- /dev/null +++ b/tests/test_crosspost_message.py @@ -0,0 +1,41 @@ +import pytest +from types import SimpleNamespace +from unittest.mock import AsyncMock + +from disagreement.http import HTTPClient +from disagreement.client import Client +from disagreement.models import Message + + +@pytest.mark.asyncio +async def test_http_crosspost_message_calls_request(): + http = HTTPClient(token="t") + http.request = AsyncMock(return_value={"id": "m"}) + data = await http.crosspost_message("c", "m") + http.request.assert_called_once_with( + "POST", + "/channels/c/messages/m/crosspost", + ) + assert data == {"id": "m"} + + +@pytest.mark.asyncio +async def test_message_crosspost_returns_message(): + payload = { + "id": "2", + "channel_id": "1", + "author": {"id": "3", "username": "u", "discriminator": "0001"}, + "content": "hi", + "timestamp": "t", + } + http = SimpleNamespace(crosspost_message=AsyncMock(return_value=payload)) + client = Client.__new__(Client) + client._http = http + client.parse_message = lambda d: Message(d, client_instance=client) + message = Message(payload, client_instance=client) + + new_msg = await message.crosspost() + + http.crosspost_message.assert_awaited_once_with("1", "2") + assert isinstance(new_msg, Message) + assert new_msg._client is client