From ca81f0c3fcdd29b16adbf39c616ab15231d21a7f Mon Sep 17 00:00:00 2001 From: Rapptz Date: Thu, 9 Feb 2017 20:47:47 -0500 Subject: [PATCH] Better group DM support. --- discord/channel.py | 105 ++++++++++++++++++++++++++++++++++++++++++++- discord/http.py | 31 +++++++++++++ discord/user.py | 39 +++++++++++++++++ 3 files changed, 174 insertions(+), 1 deletion(-) diff --git a/discord/channel.py b/discord/channel.py index 8699c25e8..af11eea28 100644 --- a/discord/channel.py +++ b/discord/channel.py @@ -359,7 +359,6 @@ class GroupChannel(discord.abc.Messageable, Hashable): def __init__(self, *, me, state, data): self._state = state - self.recipients = [state.store_user(u) for u in data['recipients']] self.id = int(data['id']) self.me = me self._update_group(data) @@ -369,6 +368,11 @@ class GroupChannel(discord.abc.Messageable, Hashable): self.icon = data.get('icon') self.name = data.get('name') + try: + self.recipients = [state.store_user(u) for u in data['recipients']] + except KeyError: + pass + if owner_id == self.me.id: self.owner = self.me else: @@ -438,6 +442,105 @@ class GroupChannel(discord.abc.Messageable, Hashable): return base + @asyncio.coroutine + def add_recipients(self, *recipients): + """|coro| + + Adds recipients to this group. + + A group can only have a maximum of 10 members. + Attempting to add more ends up in an exception. To + add a recipient to the group, you must have a relationship + with the user of type :attr:`RelationshipType.friend`. + + Parameters + ----------- + \*recipients: :class:`User` + An argument list of users to add to this group. + + Raises + ------- + HTTPException + Adding a recipient to this group failed. + """ + + # TODO: wait for the corresponding WS event + + req = self._state.http.add_group_recipient + for recipient in recipients: + yield from req(self.id, recipient.id) + + @asyncio.coroutine + def remove_recipients(self, *recipients): + """|coro| + + Removes recipients from this group. + + Parameters + ----------- + \*recipients: :class:`User` + An argument list of users to remove from this group. + + Raises + ------- + HTTPException + Removing a recipient from this group failed. + """ + + # TODO: wait for the corresponding WS event + + req = self._state.http.remove_group_recipient + for recipient in recipients: + yield from req(self.id, recipient.id) + + @asyncio.coroutine + def edit(self, **fields): + """|coro| + + Edits the group. + + Parameters + ----------- + name: Optional[str] + The new name to change the group to. + Could be ``None`` to remove the name. + icon: Optional[bytes] + A bytes-like object representing the new icon. + Could be ``None`` to remove the icon. + + Raises + ------- + HTTPException + Editing the group failed. + """ + + try: + icon_bytes = fields['icon'] + except KeyError: + pass + else: + if icon_bytes is not None: + fields['icon'] = utils._bytes_to_base64_data(icon_bytes) + + data = yield from self._state.http.edit_group(self.id, **fields) + self._update_group(data) + + @asyncio.coroutine + def leave(self): + """|coro| + + Leave the group. + + If you are the only one in the group, this deletes it as well. + + Raises + ------- + HTTPException + Leaving the group failed. + """ + + yield from self._state.http.leave_group(self.id) + def _channel_factory(channel_type): value = try_enum(ChannelType, channel_type) if value is ChannelType.text: diff --git a/discord/http.py b/discord/http.py index c8b685126..b253449c8 100644 --- a/discord/http.py +++ b/discord/http.py @@ -249,6 +249,37 @@ class HTTPClient: def logout(self): return self.request(Route('POST', '/auth/logout')) + # Group functionality + + def start_group(self, user_id, recipients): + payload = { + 'recipients': recipients + } + + return self.request(Route('POST', '/users/{user_id}/channels', user_id=user_id), json=payload) + + def leave_group(self, channel_id): + return self.request(Route('DELETE', '/channels/{channel_id}', channel_id=channel_id)) + + def add_group_recipient(self, channel_id, user_id): + r = Route('PUT', '/channels/{channel_id}/recipients/{user_id}', channel_id=channel_id, user_id=user_id) + return self.request(r) + + def remove_group_recipient(self, channel_id, user_id): + r = Route('DELETE', '/channels/{channel_id}/recipients/{user_id}', channel_id=channel_id, user_id=user_id) + return self.request(r) + + def edit_group(self, channel_id, **options): + valid_keys = ('name', 'icon') + payload = { + k: v for k, v in options.items() if k in valid_keys + } + + return self.request(Route('PATCH', '/channels/{channel_id}', channel_id=channel_id), json=payload) + + def convert_group(self, channel_id): + return self.request(Route('POST', '/channels/{channel_id}/convert', channel_id=channel_id)) + # Message management def start_private_message(self, user_id): diff --git a/discord/user.py b/discord/user.py index 47cebde5a..cadf84dbe 100644 --- a/discord/user.py +++ b/discord/user.py @@ -308,6 +308,45 @@ class ClientUser(BaseUser): # manually update data by calling __init__ explicitly. self.__init__(state=self._state, data=data) + @asyncio.coroutine + def create_group(self, *recipients): + """|coro| + + Creates a group direct message with the recipients + provided. These recipients must be have a relationship + of type :attr:`RelationshipType.friend`. + + Bot accounts cannot create a group. + + Parameters + ----------- + \*recipients + An argument list of :class:`User` to have in + your group. + + Return + ------- + :class:`GroupChannel` + The new group channel. + + Raises + ------- + HTTPException + Failed to create the group direct message. + ClientException + Attempted to create a group with only one recipient. + This does not include yourself. + """ + + from .channel import GroupChannel + + if len(recipients) < 2: + raise ClientException('You must have two or more recipients to create a group.') + + users = [str(u.id) for u in recipients] + data = yield from self._state.http.create_group(self.id, users) + return GroupChannel(me=self, data=data, state=self._state) + class User(BaseUser, discord.abc.Messageable): """Represents a Discord user.