diff --git a/disagreement/client.py b/disagreement/client.py index 7efbb11..420f9a9 100644 --- a/disagreement/client.py +++ b/disagreement/client.py @@ -1502,16 +1502,33 @@ class Client: data = await self._http.edit_webhook(webhook_id, payload) return self.parse_webhook(data) - async def delete_webhook(self, webhook_id: Snowflake) -> None: - """|coro| Delete a webhook by ID.""" - - if self._closed: - raise DisagreementException("Client is closed.") - - await self._http.delete_webhook(webhook_id) - - async def fetch_templates(self, guild_id: Snowflake) -> List["GuildTemplate"]: - """|coro| Fetch all templates for a guild.""" + async def delete_webhook(self, webhook_id: Snowflake) -> None: + """|coro| Delete a webhook by ID.""" + + if self._closed: + raise DisagreementException("Client is closed.") + + await self._http.delete_webhook(webhook_id) + + async def fetch_webhook(self, webhook_id: Snowflake) -> Optional["Webhook"]: + """|coro| Fetch a webhook by ID.""" + + if self._closed: + raise DisagreementException("Client is closed.") + + cached = self._webhooks.get(webhook_id) + if cached: + return cached + + try: + data = await self._http.get_webhook(webhook_id) + return self.parse_webhook(data) + except DisagreementException as e: + print(f"Failed to fetch webhook {webhook_id}: {e}") + return None + + async def fetch_templates(self, guild_id: Snowflake) -> List["GuildTemplate"]: + """|coro| Fetch all templates for a guild.""" if self._closed: raise DisagreementException("Client is closed.") diff --git a/disagreement/http.py b/disagreement/http.py index 32afb83..722ffe7 100644 --- a/disagreement/http.py +++ b/disagreement/http.py @@ -771,21 +771,26 @@ class HTTPClient: await self.request("DELETE", f"/invites/{code}") - async def create_webhook( - self, channel_id: "Snowflake", payload: Dict[str, Any] - ) -> "Webhook": - """Creates a webhook in the specified channel.""" + async def create_webhook( + self, channel_id: "Snowflake", payload: Dict[str, Any] + ) -> "Webhook": + """Creates a webhook in the specified channel.""" data = await self.request( "POST", f"/channels/{channel_id}/webhooks", payload=payload ) - from .models import Webhook - - return Webhook(data) - - async def edit_webhook( - self, webhook_id: "Snowflake", payload: Dict[str, Any] - ) -> "Webhook": + from .models import Webhook + + return Webhook(data) + + async def get_webhook(self, webhook_id: "Snowflake") -> Dict[str, Any]: + """Fetches a webhook by ID.""" + + return await self.request("GET", f"/webhooks/{webhook_id}") + + async def edit_webhook( + self, webhook_id: "Snowflake", payload: Dict[str, Any] + ) -> "Webhook": """Edits an existing webhook.""" data = await self.request("PATCH", f"/webhooks/{webhook_id}", payload=payload) diff --git a/tests/test_webhooks.py b/tests/test_webhooks.py index ec41110..4141197 100644 --- a/tests/test_webhooks.py +++ b/tests/test_webhooks.py @@ -195,3 +195,31 @@ async def test_webhook_send_uses_http(): http.execute_webhook.assert_awaited_once() assert isinstance(msg, Message) + + +@pytest.mark.asyncio +async def test_get_webhook_calls_request(): + http = HTTPClient(token="t") + http.request = AsyncMock(return_value={"id": "1"}) + + await http.get_webhook("1") + + http.request.assert_called_once_with("GET", "/webhooks/1") + + +@pytest.mark.asyncio +async def test_client_fetch_webhook_returns_model(): + from types import SimpleNamespace + from disagreement.client import Client + from disagreement.models import Webhook + + http = SimpleNamespace(get_webhook=AsyncMock(return_value={"id": "1"})) + client = Client(token="test") + client._http = http + client._closed = False + + webhook = await client.fetch_webhook("1") + + http.get_webhook.assert_awaited_once_with("1") + assert isinstance(webhook, Webhook) + assert client._webhooks.get("1") is webhook