diff --git a/discord/abc.py b/discord/abc.py index 924751644..160cbb4b8 100644 --- a/discord/abc.py +++ b/discord/abc.py @@ -36,6 +36,7 @@ from .context_managers import Typing from .errors import ClientException, NoMoreItems, InvalidArgument from .permissions import PermissionOverwrite, Permissions from .role import Role +from .invite import Invite from . import utils, compat class _Undefined: @@ -457,6 +458,73 @@ class GuildChannel: else: raise InvalidArgument('Invalid overwrite type provided.') + @asyncio.coroutine + def create_invite(self, **fields): + """|coro| + + Creates an instant invite. + + Parameters + ------------ + max_age : int + How long the invite should last. If it's 0 then the invite + doesn't expire. Defaults to 0. + max_uses : int + How many uses the invite could be used for. If it's 0 then there + are unlimited uses. Defaults to 0. + temporary : bool + Denotes that the invite grants temporary membership + (i.e. they get kicked after they disconnect). Defaults to False. + unique: bool + Indicates if a unique invite URL should be created. Defaults to True. + If this is set to False then it will return a previously created + invite. + + Raises + ------- + HTTPException + Invite creation failed. + + Returns + -------- + :class:`Invite` + The invite that was created. + """ + + data = yield from self._state.http.create_invite(self.id, **fields) + return Invite.from_incomplete(data=data, state=self._state) + + @asyncio.coroutine + def invites(self): + """|coro| + + Returns a list of all active instant invites from this channel. + + You must have proper permissions to get this information. + + Raises + ------- + Forbidden + You do not have proper permissions to get the information. + HTTPException + An error occurred while fetching the information. + + Returns + ------- + List[:class:`Invite`] + The list of invites that are currently active. + """ + + state = self._state + data = yield from state.http.invites_from_channel(self.id) + result = [] + + for invite in data: + invite['channel'] = self + invite['guild'] = self.guild + result.append(Invite(state=state, data=invite)) + + return result class Messageable(metaclass=abc.ABCMeta): __slots__ = () diff --git a/discord/client.py b/discord/client.py index 758ab2179..dc94ff6bd 100644 --- a/discord/client.py +++ b/discord/client.py @@ -696,59 +696,6 @@ class Client: # Invite management - def _fill_invite_data(self, data): - guild = self.connection._get_guild(data['guild']['id']) - if guild is not None: - ch_id = data['channel']['id'] - channel = guild.get_channel(ch_id) - else: - guild = Object(id=data['guild']['id']) - guild.name = data['guild']['name'] - channel = Object(id=data['channel']['id']) - channel.name = data['channel']['name'] - data['guild'] = guild - data['channel'] = channel - - @asyncio.coroutine - def create_invite(self, destination, **options): - """|coro| - - Creates an invite for the destination which could be either a - :class:`Guild` or :class:`Channel`. - - Parameters - ------------ - destination - The :class:`Guild` or :class:`Channel` to create the invite to. - max_age : int - How long the invite should last. If it's 0 then the invite - doesn't expire. Defaults to 0. - max_uses : int - How many uses the invite could be used for. If it's 0 then there - are unlimited uses. Defaults to 0. - temporary : bool - Denotes that the invite grants temporary membership - (i.e. they get kicked after they disconnect). Defaults to False. - unique: bool - Indicates if a unique invite URL should be created. Defaults to True. - If this is set to False then it will return a previously created - invite. - - Raises - ------- - HTTPException - Invite creation failed. - - Returns - -------- - :class:`Invite` - The invite that was created. - """ - - data = yield from self.http.create_invite(destination.id, **options) - self._fill_invite_data(data) - return Invite(**data) - @asyncio.coroutine def get_invite(self, url): """|coro| @@ -781,44 +728,7 @@ class Client: invite_id = self._resolve_invite(url) data = yield from self.http.get_invite(invite_id) - self._fill_invite_data(data) - return Invite(**data) - - @asyncio.coroutine - def invites_from(self, guild): - """|coro| - - Returns a list of all active instant invites from a :class:`Guild`. - - You must have proper permissions to get this information. - - Parameters - ---------- - guild : :class:`Guild` - The guild to get invites from. - - Raises - ------- - Forbidden - You do not have proper permissions to get the information. - HTTPException - An error occurred while fetching the information. - - Returns - ------- - list of :class:`Invite` - The list of invites that are currently active. - """ - - data = yield from self.http.invites_from(guild.id) - result = [] - for invite in data: - channel = guild.get_channel(invite['channel']['id']) - invite['channel'] = channel - invite['guild'] = guild - result.append(Invite(**invite)) - - return result + return Invite.from_incomplete(state=self._connection, data=data) @asyncio.coroutine def accept_invite(self, invite): diff --git a/discord/guild.py b/discord/guild.py index 5569c4c88..aeb4002be 100644 --- a/discord/guild.py +++ b/discord/guild.py @@ -729,7 +729,7 @@ class Guild(Hashable): Returns ------- - list of :class:`Invite` + List[:class:`Invite`] The list of invites that are currently active. """ @@ -743,6 +743,42 @@ class Guild(Hashable): return result + @asyncio.coroutine + def create_invite(self, **fields): + """|coro| + + Creates an instant invite. + + Parameters + ------------ + max_age : int + How long the invite should last. If it's 0 then the invite + doesn't expire. Defaults to 0. + max_uses : int + How many uses the invite could be used for. If it's 0 then there + are unlimited uses. Defaults to 0. + temporary : bool + Denotes that the invite grants temporary membership + (i.e. they get kicked after they disconnect). Defaults to False. + unique: bool + Indicates if a unique invite URL should be created. Defaults to True. + If this is set to False then it will return a previously created + invite. + + Raises + ------- + HTTPException + Invite creation failed. + + Returns + -------- + :class:`Invite` + The invite that was created. + """ + + data = yield from self._state.http.create_invite(self.id, **fields) + return Invite.from_incomplete(data=data, state=self._state) + @asyncio.coroutine def create_custom_emoji(self, *, name, image): """|coro| diff --git a/discord/invite.py b/discord/invite.py index 0ae7f02eb..17e3aecd5 100644 --- a/discord/invite.py +++ b/discord/invite.py @@ -24,9 +24,11 @@ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. """ -from .user import User +import asyncio + from .utils import parse_time from .mixins import Hashable +from .object import Object class Invite(Hashable): """Represents a Discord :class:`Guild` or :class:`Channel` invite. @@ -89,9 +91,26 @@ class Invite(Hashable): self.max_uses = data.get('max_uses') inviter_data = data.get('inviter') - self.inviter = None if inviter_data is None else User(state=state, data=inviter_data) + self.inviter = None if inviter_data is None else self._state.store_user(inviter_data) self.channel = data.get('channel') + @classmethod + def from_incomplete(cls, *, state, data): + guild_id = int(data['guild']['id']) + channel_id = int(data['channel']['id']) + guild = state._get_guild(guild_id) + if guild is not None: + channel = guild.get_channel(channel_id) + else: + guild = Object(id=guild_id) + channel = Object(id=channel_id) + guild.name = data['guild']['name'] + channel.name = data['channel']['name'] + + data['guild'] = guild + data['channel'] = channel + return cls(state=state, data=data) + def __str__(self): return self.url @@ -106,5 +125,41 @@ class Invite(Hashable): @property def url(self): """A property that retrieves the invite URL.""" - return 'http://discord.gg/{}'.format(self.id) - + return 'http://discord.gg/' + self.code + + @asyncio.coroutine + def accept(self): + """|coro| + + Accepts the instant invite and adds you to the guild + the invite is in. + + Raises + ------- + HTTPException + Accepting the invite failed. + NotFound + The invite is invalid or expired. + Forbidden + You are a bot user and cannot use this endpoint. + """ + + yield from self._state.http.accept_invite(self.code) + + @asyncio.coroutine + def delete(self): + """|coro| + + Revokes the instant invite. + + Raises + ------- + Forbidden + You do not have permissions to revoke invites. + NotFound + The invite is invalid or expired. + HTTPException + Revoking the invite failed. + """ + + yield from self._state.http.delete_invite(self.code)