diff --git a/discord/invite.py b/discord/invite.py index 28458b7a7..a70d39e4d 100644 --- a/discord/invite.py +++ b/discord/invite.py @@ -25,7 +25,8 @@ DEALINGS IN THE SOFTWARE. """ from .asset import Asset -from .utils import parse_time, snowflake_time +from .utils import parse_time, snowflake_time, _get_as_snowflake +from .object import Object from .mixins import Hashable from .enums import ChannelType, VerificationLevel, try_enum from collections import namedtuple @@ -228,7 +229,7 @@ class Invite(Hashable): How long the before the invite expires in seconds. A value of 0 indicates that it doesn't expire. code: :class:`str` The URL fragment used for the invite. - guild: Union[:class:`Guild`, :class:`PartialInviteGuild`] + guild: Union[:class:`Guild`, :class:`Object`, :class:`PartialInviteGuild`] The guild the invite is for. revoked: :class:`bool` Indicates if the invite has been revoked. @@ -248,7 +249,7 @@ class Invite(Hashable): approximate_presence_count: Optional[:class:`int`] The approximate number of members currently active in the guild. This includes idle, dnd, online, and invisible members. Offline members are excluded. - channel: Union[:class:`abc.GuildChannel`, :class:`PartialInviteChannel`] + channel: Union[:class:`abc.GuildChannel`, :class:`Object`, :class:`PartialInviteChannel`] The channel the invite is for. """ @@ -292,6 +293,21 @@ class Invite(Hashable): data['channel'] = channel return cls(state=state, data=data) + @classmethod + def from_gateway(cls, *, state, data): + guild_id = _get_as_snowflake(data, 'guild_id') + guild = state._get_guild(guild_id) + channel_id = _get_as_snowflake(data, 'channel_id') + if guild is not None: + channel = guild.get_channel(channel_id) or Object(id=channel_id) + else: + guild = Object(id=guild_id) + channel = Object(id=channel_id) + + data['guild'] = guild + data['channel'] = channel + return cls(state=state, data=data) + def __str__(self): return self.url diff --git a/discord/state.py b/discord/state.py index a215ee3ae..aea0984d5 100644 --- a/discord/state.py +++ b/discord/state.py @@ -50,6 +50,7 @@ from .enums import ChannelType, try_enum, Status, Enum from . import utils from .embeds import Embed from .object import Object +from .invite import Invite class ListenerType(Enum): chunk = 0 @@ -537,6 +538,14 @@ class ConnectionState: def parse_user_update(self, data): self.user._update(data) + def parse_invite_create(self, data): + invite = Invite.from_gateway(state=self, data=data) + self.dispatch('invite_create', invite) + + def parse_invite_delete(self, data): + invite = Invite.from_gateway(state=self, data=data) + self.dispatch('invite_delete', invite) + def parse_channel_delete(self, data): guild = self._get_guild(utils._get_as_snowflake(data, 'guild_id')) channel_id = int(data['id']) diff --git a/docs/api.rst b/docs/api.rst index a975b6240..8c22e0bc5 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -622,6 +622,37 @@ to handle it, which defaults to print a traceback and ignoring the exception. :param user: The user that got unbanned. :type user: :class:`User` +.. function:: on_invite_create(invite) + + Called when an :class:`Invite` is created. + + .. versionadded:: 1.3.0 + + .. note:: + + There is a rare possibility that the :attr:`Invite.guild` and :attr:`Invite.channel` + attributes will be of :class:`Object` rather than the respective models. + + :param invite: The invite that was created. + :type invite: :class:`Invite` + +.. function:: on_invite_delete(invite) + + Called when an :class:`Invite` is deleted. + + .. versionadded:: 1.3.0 + + .. note:: + + There is a rare possibility that the :attr:`Invite.guild` and :attr:`Invite.channel` + attributes will be of :class:`Object` rather than the respective models. + + Outside of those two attributes, the only other attribute guaranteed to be + filled by the Discord gateway for this event is :attr:`Invite.code`. + + :param invite: The invite that was deleted. + :type invite: :class:`Invite` + .. function:: on_group_join(channel, user) on_group_remove(channel, user)