diff --git a/disagreement/client.py b/disagreement/client.py index 57c38cc..79e5757 100644 --- a/disagreement/client.py +++ b/disagreement/client.py @@ -50,6 +50,7 @@ if TYPE_CHECKING: Thread, DMChannel, Webhook, + Invite, ) from .ui.view import View from .enums import ChannelType as EnumChannelType @@ -698,6 +699,13 @@ class Client: self._webhooks[webhook.id] = webhook return webhook + def parse_invite(self, data: Dict[str, Any]) -> "Invite": + """Parses invite data into an :class:`Invite`.""" + + from .models import Invite + + return Invite.from_dict(data) + async def fetch_user(self, user_id: Snowflake) -> Optional["User"]: """Fetches a user by ID from Discord.""" if self._closed: @@ -1249,6 +1257,33 @@ class Client: await self._http.delete_webhook(webhook_id) + async def create_invite( + self, channel_id: Snowflake, payload: Dict[str, Any] + ) -> "Invite": + """|coro| Create an invite for the given channel.""" + + if self._closed: + raise DisagreementException("Client is closed.") + + return await self._http.create_invite(channel_id, payload) + + async def delete_invite(self, code: str) -> None: + """|coro| Delete an invite by code.""" + + if self._closed: + raise DisagreementException("Client is closed.") + + await self._http.delete_invite(code) + + async def fetch_invites(self, channel_id: Snowflake) -> List["Invite"]: + """|coro| Fetch all invites for a channel.""" + + if self._closed: + raise DisagreementException("Client is closed.") + + data = await self._http.get_channel_invites(channel_id) + return [self.parse_invite(inv) for inv in data] + # --- Application Command Methods --- async def process_interaction(self, interaction: Interaction) -> None: """Internal method to process an interaction from the gateway.""" diff --git a/disagreement/http.py b/disagreement/http.py index 3e83404..ee1e47c 100644 --- a/disagreement/http.py +++ b/disagreement/http.py @@ -23,7 +23,7 @@ from .interactions import InteractionResponsePayload if TYPE_CHECKING: from .client import Client - from .models import Message, Webhook, File + from .models import Message, Webhook, File, Invite from .interactions import ApplicationCommand, Snowflake # Discord API constants @@ -409,6 +409,30 @@ class HTTPClient: """Fetches a channel by ID.""" return await self.request("GET", f"/channels/{channel_id}") + async def get_channel_invites( + self, channel_id: "Snowflake" + ) -> List[Dict[str, Any]]: + """Fetches the invites for a channel.""" + + return await self.request("GET", f"/channels/{channel_id}/invites") + + async def create_invite( + self, channel_id: "Snowflake", payload: Dict[str, Any] + ) -> "Invite": + """Creates an invite for a channel.""" + + data = await self.request( + "POST", f"/channels/{channel_id}/invites", payload=payload + ) + from .models import Invite + + return Invite.from_dict(data) + + async def delete_invite(self, code: str) -> None: + """Deletes an invite by code.""" + + await self.request("DELETE", f"/invites/{code}") + async def create_webhook( self, channel_id: "Snowflake", payload: Dict[str, Any] ) -> "Webhook": diff --git a/disagreement/models.py b/disagreement/models.py index 1b28207..1fc1f45 100644 --- a/disagreement/models.py +++ b/disagreement/models.py @@ -6,6 +6,7 @@ Data models for Discord objects. import asyncio import json +from dataclasses import dataclass from typing import Any, AsyncIterator, Dict, List, Optional, TYPE_CHECKING, Union import aiohttp # pylint: disable=import-error @@ -1978,6 +1979,41 @@ class Reaction: return f"" +@dataclass +class Invite: + """Represents a Discord invite.""" + + code: str + channel_id: Optional[str] + guild_id: Optional[str] + inviter_id: Optional[str] + uses: Optional[int] + max_uses: Optional[int] + max_age: Optional[int] + temporary: Optional[bool] + created_at: Optional[str] + + @classmethod + def from_dict(cls, data: Dict[str, Any]) -> "Invite": + channel = data.get("channel") + guild = data.get("guild") + inviter = data.get("inviter") + return cls( + code=data["code"], + channel_id=(channel or {}).get("id") if channel else data.get("channel_id"), + guild_id=(guild or {}).get("id") if guild else data.get("guild_id"), + inviter_id=(inviter or {}).get("id"), + uses=data.get("uses"), + max_uses=data.get("max_uses"), + max_age=data.get("max_age"), + temporary=data.get("temporary"), + created_at=data.get("created_at"), + ) + + def __repr__(self) -> str: + return f"" + + class GuildMemberRemove: """Represents a GUILD_MEMBER_REMOVE event.""" diff --git a/docs/invites.md b/docs/invites.md new file mode 100644 index 0000000..138eca9 --- /dev/null +++ b/docs/invites.md @@ -0,0 +1,24 @@ +# Working with Invites + +The library exposes helper methods for creating and deleting invites. + +## Create an Invite + +```python +invite = await client.create_invite("1234567890", {"max_age": 3600}) +print(invite.code) +``` + +## Delete an Invite + +```python +await client.delete_invite(invite.code) +``` + +## List Invites + +```python +invites = await client.fetch_invites("1234567890") +for inv in invites: + print(inv.code, inv.uses) +```