Remove userbot functionality
This has a lot of legacy and cruft so there may be some stuff I've missed but this first pass is enough to get a clear separation.
This commit is contained in:
		| @@ -22,19 +22,17 @@ import logging | ||||
|  | ||||
| from .client import Client | ||||
| from .appinfo import AppInfo | ||||
| from .user import User, ClientUser, Profile | ||||
| from .user import User, ClientUser | ||||
| from .emoji import Emoji | ||||
| from .partial_emoji import PartialEmoji | ||||
| from .activity import * | ||||
| from .channel import * | ||||
| from .guild import Guild | ||||
| from .flags import * | ||||
| from .relationship import Relationship | ||||
| from .member import Member, VoiceState | ||||
| from .message import * | ||||
| from .asset import Asset | ||||
| from .errors import * | ||||
| from .calls import CallMessage, GroupCall | ||||
| from .permissions import Permissions, PermissionOverwrite | ||||
| from .role import Role, RoleTags | ||||
| from .file import File | ||||
|   | ||||
							
								
								
									
										174
									
								
								discord/calls.py
									
									
									
									
									
								
							
							
						
						
									
										174
									
								
								discord/calls.py
									
									
									
									
									
								
							| @@ -1,174 +0,0 @@ | ||||
| """ | ||||
| The MIT License (MIT) | ||||
|  | ||||
| Copyright (c) 2015-present Rapptz | ||||
|  | ||||
| Permission is hereby granted, free of charge, to any person obtaining a | ||||
| copy of this software and associated documentation files (the "Software"), | ||||
| to deal in the Software without restriction, including without limitation | ||||
| the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||||
| and/or sell copies of the Software, and to permit persons to whom the | ||||
| Software is furnished to do so, subject to the following conditions: | ||||
|  | ||||
| The above copyright notice and this permission notice shall be included in | ||||
| all copies or substantial portions of the Software. | ||||
|  | ||||
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS | ||||
| OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
| FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
| AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
| LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||||
| FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||||
| DEALINGS IN THE SOFTWARE. | ||||
| """ | ||||
|  | ||||
| import datetime | ||||
|  | ||||
| from . import utils | ||||
| from .enums import VoiceRegion, try_enum | ||||
| from .member import VoiceState | ||||
|  | ||||
| class CallMessage: | ||||
|     """Represents a group call message from Discord. | ||||
|  | ||||
|     This is only received in cases where the message type is equivalent to | ||||
|     :attr:`MessageType.call`. | ||||
|  | ||||
|     .. deprecated:: 1.7 | ||||
|  | ||||
|     Attributes | ||||
|     ----------- | ||||
|     ended_timestamp: Optional[:class:`datetime.datetime`] | ||||
|         A naive UTC datetime object that represents the time that the call has ended. | ||||
|     participants: List[:class:`User`] | ||||
|         The list of users that are participating in this call. | ||||
|     message: :class:`Message` | ||||
|         The message associated with this call message. | ||||
|     """ | ||||
|  | ||||
|     def __init__(self, message, **kwargs): | ||||
|         self.message = message | ||||
|         self.ended_timestamp = utils.parse_time(kwargs.get('ended_timestamp')) | ||||
|         self.participants = kwargs.get('participants') | ||||
|  | ||||
|     @property | ||||
|     def call_ended(self): | ||||
|         """:class:`bool`: Indicates if the call has ended. | ||||
|  | ||||
|         .. deprecated:: 1.7 | ||||
|         """ | ||||
|         return self.ended_timestamp is not None | ||||
|  | ||||
|     @property | ||||
|     def channel(self): | ||||
|         r""":class:`GroupChannel`\: The private channel associated with this message. | ||||
|  | ||||
|         .. deprecated:: 1.7 | ||||
|         """ | ||||
|         return self.message.channel | ||||
|  | ||||
|     @property | ||||
|     def duration(self): | ||||
|         """Queries the duration of the call. | ||||
|  | ||||
|         If the call has not ended then the current duration will | ||||
|         be returned. | ||||
|  | ||||
|         .. deprecated:: 1.7 | ||||
|  | ||||
|         Returns | ||||
|         --------- | ||||
|         :class:`datetime.timedelta` | ||||
|             The timedelta object representing the duration. | ||||
|         """ | ||||
|         if self.ended_timestamp is None: | ||||
|             return datetime.datetime.utcnow() - self.message.created_at | ||||
|         else: | ||||
|             return self.ended_timestamp - self.message.created_at | ||||
|  | ||||
| class GroupCall: | ||||
|     """Represents the actual group call from Discord. | ||||
|  | ||||
|     This is accompanied with a :class:`CallMessage` denoting the information. | ||||
|  | ||||
|     .. deprecated:: 1.7 | ||||
|  | ||||
|     Attributes | ||||
|     ----------- | ||||
|     call: :class:`CallMessage` | ||||
|         The call message associated with this group call. | ||||
|     unavailable: :class:`bool` | ||||
|         Denotes if this group call is unavailable. | ||||
|     ringing: List[:class:`User`] | ||||
|         A list of users that are currently being rung to join the call. | ||||
|     region: :class:`VoiceRegion` | ||||
|         The guild region the group call is being hosted on. | ||||
|     """ | ||||
|  | ||||
|     def __init__(self, **kwargs): | ||||
|         self.call = kwargs.get('call') | ||||
|         self.unavailable = kwargs.get('unavailable') | ||||
|         self._voice_states = {} | ||||
|  | ||||
|         for state in kwargs.get('voice_states', []): | ||||
|             self._update_voice_state(state) | ||||
|  | ||||
|         self._update(**kwargs) | ||||
|  | ||||
|     def _update(self, **kwargs): | ||||
|         self.region = try_enum(VoiceRegion, kwargs.get('region')) | ||||
|         lookup = {u.id: u for u in self.call.channel.recipients} | ||||
|         me = self.call.channel.me | ||||
|         lookup[me.id] = me | ||||
|         self.ringing = list(filter(None, map(lookup.get, kwargs.get('ringing', [])))) | ||||
|  | ||||
|     def _update_voice_state(self, data): | ||||
|         user_id = int(data['user_id']) | ||||
|         # left the voice channel? | ||||
|         if data['channel_id'] is None: | ||||
|             self._voice_states.pop(user_id, None) | ||||
|         else: | ||||
|             self._voice_states[user_id] = VoiceState(data=data, channel=self.channel) | ||||
|  | ||||
|     @property | ||||
|     def connected(self): | ||||
|         """List[:class:`User`]: A property that returns all users that are currently in this call. | ||||
|          | ||||
|         .. deprecated:: 1.7 | ||||
|         """ | ||||
|         ret = [u for u in self.channel.recipients if self.voice_state_for(u) is not None] | ||||
|         me = self.channel.me | ||||
|         if self.voice_state_for(me) is not None: | ||||
|             ret.append(me) | ||||
|  | ||||
|         return ret | ||||
|  | ||||
|     @property | ||||
|     def channel(self): | ||||
|         r""":class:`GroupChannel`\: Returns the channel the group call is in. | ||||
|  | ||||
|         .. deprecated:: 1.7 | ||||
|         """ | ||||
|         return self.call.channel | ||||
|  | ||||
|     @utils.deprecated() | ||||
|     def voice_state_for(self, user): | ||||
|         """Retrieves the :class:`VoiceState` for a specified :class:`User`. | ||||
|  | ||||
|         If the :class:`User` has no voice state then this function returns | ||||
|         ``None``. | ||||
|  | ||||
|         .. deprecated:: 1.7 | ||||
|  | ||||
|         Parameters | ||||
|         ------------ | ||||
|         user: :class:`User` | ||||
|             The user to retrieve the voice state for. | ||||
|  | ||||
|         Returns | ||||
|         -------- | ||||
|         Optional[:class:`VoiceState`] | ||||
|             The voice state associated with this user. | ||||
|         """ | ||||
|  | ||||
|         return self._voice_states.get(user.id) | ||||
| @@ -311,10 +311,6 @@ class TextChannel(discord.abc.Messageable, discord.abc.GuildChannel, Hashable): | ||||
|         account). The :attr:`~Permissions.read_message_history` permission is | ||||
|         also needed to retrieve message history. | ||||
|  | ||||
|         Internally, this employs a different number of strategies depending | ||||
|         on the conditions met such as if a bulk delete is possible or if | ||||
|         the account is a user bot or not. | ||||
|  | ||||
|         Examples | ||||
|         --------- | ||||
|  | ||||
| @@ -345,8 +341,7 @@ class TextChannel(discord.abc.Messageable, discord.abc.GuildChannel, Hashable): | ||||
|         bulk: :class:`bool` | ||||
|             If ``True``, use bulk delete. Setting this to ``False`` is useful for mass-deleting | ||||
|             a bot's own messages without :attr:`Permissions.manage_messages`. When ``True``, will | ||||
|             fall back to single delete if current account is a user bot (now deprecated), or if messages are | ||||
|             older than two weeks. | ||||
|             fall back to single delete if messages are older than two weeks. | ||||
|  | ||||
|         Raises | ||||
|         ------- | ||||
| @@ -369,7 +364,7 @@ class TextChannel(discord.abc.Messageable, discord.abc.GuildChannel, Hashable): | ||||
|         count = 0 | ||||
|  | ||||
|         minimum_time = int((time.time() - 14 * 24 * 60 * 60) * 1000.0 - 1420070400000) << 22 | ||||
|         strategy = self.delete_messages if self._state.is_bot and bulk else _single_delete_strategy | ||||
|         strategy = self.delete_messages if bulk else _single_delete_strategy | ||||
|  | ||||
|         while True: | ||||
|             try: | ||||
| @@ -1442,95 +1437,6 @@ class GroupChannel(discord.abc.Messageable, Hashable): | ||||
|  | ||||
|         return base | ||||
|  | ||||
|     @utils.deprecated() | ||||
|     async def add_recipients(self, *recipients): | ||||
|         r"""|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`. | ||||
|  | ||||
|         .. deprecated:: 1.7 | ||||
|  | ||||
|         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: | ||||
|             await req(self.id, recipient.id) | ||||
|  | ||||
|     @utils.deprecated() | ||||
|     async def remove_recipients(self, *recipients): | ||||
|         r"""|coro| | ||||
|  | ||||
|         Removes recipients from this group. | ||||
|  | ||||
|         .. deprecated:: 1.7 | ||||
|  | ||||
|         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: | ||||
|             await req(self.id, recipient.id) | ||||
|  | ||||
|     @utils.deprecated() | ||||
|     async def edit(self, **fields): | ||||
|         """|coro| | ||||
|  | ||||
|         Edits the group. | ||||
|  | ||||
|         .. deprecated:: 1.7 | ||||
|  | ||||
|         Parameters | ||||
|         ----------- | ||||
|         name: Optional[:class:`str`] | ||||
|             The new name to change the group to. | ||||
|             Could be ``None`` to remove the name. | ||||
|         icon: Optional[:class:`bytes`] | ||||
|             A :term:`py: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 = await self._state.http.edit_group(self.id, **fields) | ||||
|         self._update_group(data) | ||||
|  | ||||
|     async def leave(self): | ||||
|         """|coro| | ||||
|  | ||||
|   | ||||
| @@ -30,7 +30,7 @@ import traceback | ||||
|  | ||||
| import aiohttp | ||||
|  | ||||
| from .user import User, Profile | ||||
| from .user import User | ||||
| from .invite import Invite | ||||
| from .template import Template | ||||
| from .widget import Widget | ||||
| @@ -245,10 +245,7 @@ class Client: | ||||
|  | ||||
|     def _get_state(self, **options): | ||||
|         return ConnectionState(dispatch=self.dispatch, handlers=self._handlers, | ||||
|                                hooks=self._hooks, syncer=self._syncer, http=self.http, loop=self.loop, **options) | ||||
|  | ||||
|     async def _syncer(self, guilds): | ||||
|         await self.ws.request_sync(guilds) | ||||
|                                hooks=self._hooks, http=self.http, loop=self.loop, **options) | ||||
|  | ||||
|     def _handle_ready(self): | ||||
|         self._ready.set() | ||||
| @@ -454,7 +451,7 @@ class Client: | ||||
|  | ||||
|     # login state management | ||||
|  | ||||
|     async def login(self, token, *, bot=True): | ||||
|     async def login(self, token): | ||||
|         """|coro| | ||||
|  | ||||
|         Logs in the client with the specified credentials. | ||||
| @@ -473,11 +470,6 @@ class Client: | ||||
|         token: :class:`str` | ||||
|             The authentication token. Do not prefix this token with | ||||
|             anything as the library will do it for you. | ||||
|         bot: :class:`bool` | ||||
|             Keyword argument that specifies if the account logging on is a bot | ||||
|             token or not. | ||||
|  | ||||
|             .. deprecated:: 1.7 | ||||
|  | ||||
|         Raises | ||||
|         ------ | ||||
| @@ -490,8 +482,7 @@ class Client: | ||||
|         """ | ||||
|  | ||||
|         log.info('logging in using static token') | ||||
|         await self.http.static_login(token.strip(), bot=bot) | ||||
|         self._connection.is_bot = bot | ||||
|         await self.http.static_login(token.strip()) | ||||
|  | ||||
|     @utils.deprecated('Client.close') | ||||
|     async def logout(self): | ||||
| @@ -628,7 +619,7 @@ class Client: | ||||
|         self._connection.clear() | ||||
|         self.http.recreate() | ||||
|  | ||||
|     async def start(self, *args, **kwargs): | ||||
|     async def start(self, token, *, reconnect=True): | ||||
|         """|coro| | ||||
|  | ||||
|         A shorthand coroutine for :meth:`login` + :meth:`connect`. | ||||
| @@ -638,13 +629,7 @@ class Client: | ||||
|         TypeError | ||||
|             An unexpected keyword argument was received. | ||||
|         """ | ||||
|         bot = kwargs.pop('bot', True) | ||||
|         reconnect = kwargs.pop('reconnect', True) | ||||
|  | ||||
|         if kwargs: | ||||
|             raise TypeError(f"unexpected keyword argument(s) {list(kwargs.keys())}") | ||||
|  | ||||
|         await self.login(*args, bot=bot) | ||||
|         await self.login(token) | ||||
|         await self.connect(reconnect=reconnect) | ||||
|  | ||||
|     def run(self, *args, **kwargs): | ||||
| @@ -1364,51 +1349,6 @@ class Client: | ||||
|         data = await self.http.get_user(user_id) | ||||
|         return User(state=self._connection, data=data) | ||||
|  | ||||
|     @utils.deprecated() | ||||
|     async def fetch_user_profile(self, user_id): | ||||
|         """|coro| | ||||
|  | ||||
|         Gets an arbitrary user's profile. | ||||
|  | ||||
|         .. deprecated:: 1.7 | ||||
|  | ||||
|         .. note:: | ||||
|  | ||||
|             This can only be used by non-bot accounts. | ||||
|  | ||||
|         Parameters | ||||
|         ------------ | ||||
|         user_id: :class:`int` | ||||
|             The ID of the user to fetch their profile for. | ||||
|  | ||||
|         Raises | ||||
|         ------- | ||||
|         :exc:`.Forbidden` | ||||
|             Not allowed to fetch profiles. | ||||
|         :exc:`.HTTPException` | ||||
|             Fetching the profile failed. | ||||
|  | ||||
|         Returns | ||||
|         -------- | ||||
|         :class:`.Profile` | ||||
|             The profile of the user. | ||||
|         """ | ||||
|  | ||||
|         state = self._connection | ||||
|         data = await self.http.get_user_profile(user_id) | ||||
|  | ||||
|         def transform(d): | ||||
|             return state._get_guild(int(d['id'])) | ||||
|  | ||||
|         since = data.get('premium_since') | ||||
|         mutual_guilds = list(filter(None, map(transform, data.get('mutual_guilds', [])))) | ||||
|         user = data['user'] | ||||
|         return Profile(flags=user.get('flags', 0), | ||||
|                        premium_since=utils.parse_time(since), | ||||
|                        mutual_guilds=mutual_guilds, | ||||
|                        user=User(data=user, state=state), | ||||
|                        connected_accounts=data['connected_accounts']) | ||||
|  | ||||
|     async def fetch_channel(self, channel_id): | ||||
|         """|coro| | ||||
|  | ||||
|   | ||||
| @@ -35,18 +35,12 @@ __all__ = ( | ||||
|     'ContentFilter', | ||||
|     'Status', | ||||
|     'DefaultAvatar', | ||||
|     'RelationshipType', | ||||
|     'AuditLogAction', | ||||
|     'AuditLogActionCategory', | ||||
|     'UserFlags', | ||||
|     'ActivityType', | ||||
|     'HypeSquadHouse', | ||||
|     'NotificationLevel', | ||||
|     'PremiumType', | ||||
|     'UserContentFilter', | ||||
|     'FriendFlags', | ||||
|     'TeamMembershipState', | ||||
|     'Theme', | ||||
|     'WebhookType', | ||||
|     'ExpireBehaviour', | ||||
|     'ExpireBehavior', | ||||
| @@ -242,22 +236,6 @@ class ContentFilter(Enum): | ||||
|     def __str__(self): | ||||
|         return self.name | ||||
|  | ||||
| class UserContentFilter(Enum): | ||||
|     disabled    = 0 | ||||
|     friends     = 1 | ||||
|     all_messages = 2 | ||||
|  | ||||
| class FriendFlags(Enum): | ||||
|     noone = 0 | ||||
|     mutual_guilds = 1 | ||||
|     mutual_friends = 2 | ||||
|     guild_and_friends = 3 | ||||
|     everyone = 4 | ||||
|  | ||||
| class Theme(Enum): | ||||
|     light = 'light' | ||||
|     dark = 'dark' | ||||
|  | ||||
| class Status(Enum): | ||||
|     online = 'online' | ||||
|     offline = 'offline' | ||||
| @@ -280,12 +258,6 @@ class DefaultAvatar(Enum): | ||||
|     def __str__(self): | ||||
|         return self.name | ||||
|  | ||||
| class RelationshipType(Enum): | ||||
|     friend           = 1 | ||||
|     blocked          = 2 | ||||
|     incoming_request = 3 | ||||
|     outgoing_request = 4 | ||||
|  | ||||
| class NotificationLevel(Enum): | ||||
|     all_messages  = 0 | ||||
|     only_mentions = 1 | ||||
| @@ -427,15 +399,6 @@ class ActivityType(Enum): | ||||
|     def __int__(self): | ||||
|         return self.value | ||||
|  | ||||
| class HypeSquadHouse(Enum): | ||||
|     bravery = 1 | ||||
|     brilliance = 2 | ||||
|     balance = 3 | ||||
|  | ||||
| class PremiumType(Enum): | ||||
|     nitro_classic = 1 | ||||
|     nitro = 2 | ||||
|  | ||||
| class TeamMembershipState(Enum): | ||||
|     invited = 1 | ||||
|     accepted = 2 | ||||
|   | ||||
| @@ -378,9 +378,6 @@ class DiscordWebSocket: | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         if not self._connection.is_bot: | ||||
|             payload['d']['synced_guilds'] = [] | ||||
|  | ||||
|         if self.shard_id is not None and self.shard_count is not None: | ||||
|             payload['d']['shard'] = [self.shard_id, self.shard_count] | ||||
|  | ||||
| @@ -622,13 +619,6 @@ class DiscordWebSocket: | ||||
|         log.debug('Sending "%s" to change status', sent) | ||||
|         await self.send(sent) | ||||
|  | ||||
|     async def request_sync(self, guild_ids): | ||||
|         payload = { | ||||
|             'op': self.GUILD_SYNC, | ||||
|             'd': list(guild_ids) | ||||
|         } | ||||
|         await self.send_as_json(payload) | ||||
|  | ||||
|     async def request_chunks(self, guild_id, query=None, *, limit, user_ids=None, presences=False, nonce=None): | ||||
|         payload = { | ||||
|             'op': self.REQUEST_MEMBERS, | ||||
|   | ||||
| @@ -2090,29 +2090,6 @@ class Guild(Hashable): | ||||
|         payload['max_age'] = 0 | ||||
|         return Invite(state=self._state, data=payload) | ||||
|  | ||||
|     @utils.deprecated() | ||||
|     def ack(self): | ||||
|         """|coro| | ||||
|  | ||||
|         Marks every message in this guild as read. | ||||
|  | ||||
|         The user must not be a bot user. | ||||
|  | ||||
|         .. deprecated:: 1.7 | ||||
|  | ||||
|         Raises | ||||
|         ------- | ||||
|         HTTPException | ||||
|             Acking failed. | ||||
|         ClientException | ||||
|             You must not be a bot user. | ||||
|         """ | ||||
|  | ||||
|         state = self._state | ||||
|         if state.is_bot: | ||||
|             raise ClientException('Must not be a bot account to ack messages.') | ||||
|         return state.http.ack_guild(self.id) | ||||
|  | ||||
|     def audit_logs(self, *, limit=100, before=None, after=None, oldest_first=None, user=None, action=None): | ||||
|         """Returns an :class:`AsyncIterator` that enables receiving the guild's audit logs. | ||||
|  | ||||
|   | ||||
| @@ -147,7 +147,7 @@ class HTTPClient: | ||||
|         } | ||||
|  | ||||
|         if self.token is not None: | ||||
|             headers['Authorization'] = 'Bot ' + self.token if self.bot_token else self.token | ||||
|             headers['Authorization'] = 'Bot ' + self.token | ||||
|         # some checking if it's a JSON request | ||||
|         if 'json' in kwargs: | ||||
|             headers['Content-Type'] = 'application/json' | ||||
| @@ -281,23 +281,18 @@ class HTTPClient: | ||||
|         if self.__session: | ||||
|             await self.__session.close() | ||||
|  | ||||
|     def _token(self, token, *, bot=True): | ||||
|         self.token = token | ||||
|         self.bot_token = bot | ||||
|         self._ack_token = None | ||||
|  | ||||
|     # login management | ||||
|  | ||||
|     async def static_login(self, token, *, bot): | ||||
|     async def static_login(self, token): | ||||
|         # Necessary to get aiohttp to stop complaining about session creation | ||||
|         self.__session = aiohttp.ClientSession(connector=self.connector, ws_response_class=DiscordClientWebSocketResponse) | ||||
|         old_token, old_bot = self.token, self.bot_token | ||||
|         self._token(token, bot=bot) | ||||
|         old_token = self.token | ||||
|         self.token = token | ||||
|  | ||||
|         try: | ||||
|             data = await self.request(Route('GET', '/users/@me')) | ||||
|         except HTTPException as exc: | ||||
|             self._token(old_token, bot=old_bot) | ||||
|             self.token = old_token | ||||
|             if exc.response.status == 401: | ||||
|                 raise LoginFailure('Improper token has been passed.') from exc | ||||
|             raise | ||||
| @@ -319,25 +314,6 @@ class HTTPClient: | ||||
|     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): | ||||
| @@ -410,14 +386,6 @@ class HTTPClient: | ||||
|  | ||||
|         return self.request(r, form=form, files=files) | ||||
|  | ||||
|     async def ack_message(self, channel_id, message_id): | ||||
|         r = Route('POST', '/channels/{channel_id}/messages/{message_id}/ack', channel_id=channel_id, message_id=message_id) | ||||
|         data = await self.request(r, json={'token': self._ack_token}) | ||||
|         self._ack_token = data['token'] | ||||
|  | ||||
|     def ack_guild(self, guild_id): | ||||
|         return self.request(Route('POST', '/guilds/{guild_id}/ack', guild_id=guild_id)) | ||||
|  | ||||
|     def delete_message(self, channel_id, message_id, *, reason=None): | ||||
|         r = Route('DELETE', '/channels/{channel_id}/messages/{message_id}', channel_id=channel_id, message_id=message_id) | ||||
|         return self.request(r, reason=reason) | ||||
| @@ -543,18 +511,12 @@ class HTTPClient: | ||||
|  | ||||
|         return self.request(r, json=payload, reason=reason) | ||||
|  | ||||
|     def edit_profile(self, password, username, avatar, **fields): | ||||
|         payload = { | ||||
|             'password': password, | ||||
|             'username': username, | ||||
|             'avatar': avatar | ||||
|         } | ||||
|  | ||||
|         if 'email' in fields: | ||||
|             payload['email'] = fields['email'] | ||||
|  | ||||
|         if 'new_password' in fields: | ||||
|             payload['new_password'] = fields['new_password'] | ||||
|     def edit_profile(self, username, avatar): | ||||
|         payload = {} | ||||
|         if avatar is not None: | ||||
|             payload['avatar'] = avatar | ||||
|         if username is not None: | ||||
|             payload['username'] = username | ||||
|  | ||||
|         return self.request(Route('PATCH', '/users/@me'), json=payload) | ||||
|  | ||||
| @@ -933,28 +895,6 @@ class HTTPClient: | ||||
|     def move_member(self, user_id, guild_id, channel_id, *, reason=None): | ||||
|         return self.edit_member(guild_id=guild_id, user_id=user_id, channel_id=channel_id, reason=reason) | ||||
|  | ||||
|     # Relationship related | ||||
|  | ||||
|     def remove_relationship(self, user_id): | ||||
|         r = Route('DELETE', '/users/@me/relationships/{user_id}', user_id=user_id) | ||||
|         return self.request(r) | ||||
|  | ||||
|     def add_relationship(self, user_id, type=None): | ||||
|         r = Route('PUT', '/users/@me/relationships/{user_id}', user_id=user_id) | ||||
|         payload = {} | ||||
|         if type is not None: | ||||
|             payload['type'] = type | ||||
|  | ||||
|         return self.request(r, json=payload) | ||||
|  | ||||
|     def send_friend_request(self, username, discriminator): | ||||
|         r = Route('POST', '/users/@me/relationships') | ||||
|         payload = { | ||||
|             'username': username, | ||||
|             'discriminator': int(discriminator) | ||||
|         } | ||||
|         return self.request(r, json=payload) | ||||
|  | ||||
|     # Misc | ||||
|  | ||||
|     def application_info(self): | ||||
| @@ -985,19 +925,3 @@ class HTTPClient: | ||||
|  | ||||
|     def get_user(self, user_id): | ||||
|         return self.request(Route('GET', '/users/{user_id}', user_id=user_id)) | ||||
|  | ||||
|     def get_user_profile(self, user_id): | ||||
|         return self.request(Route('GET', '/users/{user_id}/profile', user_id=user_id)) | ||||
|  | ||||
|     def get_mutual_friends(self, user_id): | ||||
|         return self.request(Route('GET', '/users/{user_id}/relationships', user_id=user_id)) | ||||
|  | ||||
|     def change_hypesquad_house(self, house_id): | ||||
|         payload = {'house_id': house_id} | ||||
|         return self.request(Route('POST', '/hypesquad/online'), json=payload) | ||||
|  | ||||
|     def leave_hypesquad_house(self): | ||||
|         return self.request(Route('DELETE', '/hypesquad/online')) | ||||
|  | ||||
|     def edit_settings(self, **payload): | ||||
|         return self.request(Route('PATCH', '/users/@me/settings'), json=payload) | ||||
|   | ||||
| @@ -31,7 +31,6 @@ from . import utils | ||||
| from .reaction import Reaction | ||||
| from .emoji import Emoji | ||||
| from .partial_emoji import PartialEmoji | ||||
| from .calls import CallMessage | ||||
| from .enums import MessageType, ChannelType, try_enum | ||||
| from .errors import InvalidArgument, ClientException, HTTPException | ||||
| from .embeds import Embed | ||||
| @@ -453,12 +452,6 @@ class Message(Hashable): | ||||
|     channel: Union[:class:`abc.Messageable`] | ||||
|         The :class:`TextChannel` that the message was sent from. | ||||
|         Could be a :class:`DMChannel` or :class:`GroupChannel` if it's a private message. | ||||
|     call: Optional[:class:`CallMessage`] | ||||
|         The call that the message refers to. This is only applicable to messages of type | ||||
|         :attr:`MessageType.call`. | ||||
|  | ||||
|         .. deprecated:: 1.7 | ||||
|  | ||||
|     reference: Optional[:class:`~discord.MessageReference`] | ||||
|         The message that this message references. This is only applicable to messages of | ||||
|         type :attr:`MessageType.pins_add`, crossposted messages created by a | ||||
| @@ -534,7 +527,7 @@ class Message(Hashable): | ||||
|                  'mention_everyone', 'embeds', 'id', 'mentions', 'author', | ||||
|                  '_cs_channel_mentions', '_cs_raw_mentions', 'attachments', | ||||
|                  '_cs_clean_content', '_cs_raw_channel_mentions', 'nonce', 'pinned', | ||||
|                  'role_mentions', '_cs_raw_role_mentions', 'type', 'call', 'flags', | ||||
|                  'role_mentions', '_cs_raw_role_mentions', 'type', 'flags', | ||||
|                  '_cs_system_content', '_cs_guild', '_state', 'reactions', 'reference', | ||||
|                  'application', 'activity', 'stickers') | ||||
|  | ||||
| @@ -548,7 +541,6 @@ class Message(Hashable): | ||||
|         self.application = data.get('application') | ||||
|         self.activity = data.get('activity') | ||||
|         self.channel = channel | ||||
|         self.call = None | ||||
|         self._edited_timestamp = utils.parse_time(data['edited_timestamp']) | ||||
|         self.type = try_enum(MessageType, data['type']) | ||||
|         self.pinned = data['pinned'] | ||||
| @@ -581,7 +573,7 @@ class Message(Hashable): | ||||
|  | ||||
|                     ref.resolved = self.__class__(channel=chan, data=resolved, state=state) | ||||
|  | ||||
|         for handler in ('author', 'member', 'mentions', 'mention_roles', 'call', 'flags'): | ||||
|         for handler in ('author', 'member', 'mentions', 'mention_roles', 'flags'): | ||||
|             try: | ||||
|                 getattr(self, f'_handle_{handler}')(data[handler]) | ||||
|             except KeyError: | ||||
| @@ -749,26 +741,6 @@ class Message(Hashable): | ||||
|                 if role is not None: | ||||
|                     self.role_mentions.append(role) | ||||
|  | ||||
|     def _handle_call(self, call): | ||||
|         if call is None or self.type is not MessageType.call: | ||||
|             self.call = None | ||||
|             return | ||||
|  | ||||
|         # we get the participant source from the mentions array or | ||||
|         # the author | ||||
|  | ||||
|         participants = [] | ||||
|         for uid in map(int, call.get('participants', [])): | ||||
|             if uid == self.author.id: | ||||
|                 participants.append(self.author) | ||||
|             else: | ||||
|                 user = utils.find(lambda u: u.id == uid, self.mentions) | ||||
|                 if user is not None: | ||||
|                     participants.append(user) | ||||
|  | ||||
|         call['participants'] = participants | ||||
|         self.call = CallMessage(message=self, **call) | ||||
|  | ||||
|     def _rebind_channel_reference(self, new_channel): | ||||
|         self.channel = new_channel | ||||
|  | ||||
| @@ -937,19 +909,6 @@ class Message(Hashable): | ||||
|             created_at_ms = int((self.created_at - datetime.datetime(1970, 1, 1)).total_seconds() * 1000) | ||||
|             return formats[created_at_ms % len(formats)].format(self.author.name) | ||||
|  | ||||
|         if self.type is MessageType.call: | ||||
|             # we're at the call message type now, which is a bit more complicated. | ||||
|             # we can make the assumption that Message.channel is a PrivateChannel | ||||
|             # with the type ChannelType.group or ChannelType.private | ||||
|             call_ended = self.call.ended_timestamp is not None | ||||
|  | ||||
|             if self.channel.me in self.call.participants: | ||||
|                 return f'{self.author.name} started a call.' | ||||
|             elif call_ended: | ||||
|                 return f'You missed a call from {self.author.name}' | ||||
|             else: | ||||
|                 return '{0.author.name} started a call \N{EM DASH} Join the call.'.format(self) | ||||
|  | ||||
|         if self.type is MessageType.premium_guild_subscription: | ||||
|             return f'{self.author.name} just boosted the server!' | ||||
|  | ||||
| @@ -1303,29 +1262,6 @@ class Message(Hashable): | ||||
|         """ | ||||
|         await self._state.http.clear_reactions(self.channel.id, self.id) | ||||
|  | ||||
|     @utils.deprecated() | ||||
|     async def ack(self): | ||||
|         """|coro| | ||||
|  | ||||
|         Marks this message as read. | ||||
|  | ||||
|         The user must not be a bot user. | ||||
|  | ||||
|         .. deprecated:: 1.7 | ||||
|  | ||||
|         Raises | ||||
|         ------- | ||||
|         HTTPException | ||||
|             Acking failed. | ||||
|         ClientException | ||||
|             You must not be a bot user. | ||||
|         """ | ||||
|  | ||||
|         state = self._state | ||||
|         if state.is_bot: | ||||
|             raise ClientException('Must not be a bot account to ack messages.') | ||||
|         return await state.http.ack_message(self.channel.id, self.id) | ||||
|  | ||||
|     async def reply(self, content=None, **kwargs): | ||||
|         """|coro| | ||||
|  | ||||
|   | ||||
| @@ -1,85 +0,0 @@ | ||||
| """ | ||||
| The MIT License (MIT) | ||||
|  | ||||
| Copyright (c) 2015-present Rapptz | ||||
|  | ||||
| Permission is hereby granted, free of charge, to any person obtaining a | ||||
| copy of this software and associated documentation files (the "Software"), | ||||
| to deal in the Software without restriction, including without limitation | ||||
| the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||||
| and/or sell copies of the Software, and to permit persons to whom the | ||||
| Software is furnished to do so, subject to the following conditions: | ||||
|  | ||||
| The above copyright notice and this permission notice shall be included in | ||||
| all copies or substantial portions of the Software. | ||||
|  | ||||
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS | ||||
| OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
| FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
| AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
| LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||||
| FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||||
| DEALINGS IN THE SOFTWARE. | ||||
| """ | ||||
|  | ||||
| from .enums import RelationshipType, try_enum | ||||
| from . import utils | ||||
|  | ||||
| class Relationship: | ||||
|     """Represents a relationship in Discord. | ||||
|  | ||||
|     A relationship is like a friendship, a person who is blocked, etc. | ||||
|     Only non-bot accounts can have relationships. | ||||
|  | ||||
|     .. deprecated:: 1.7 | ||||
|  | ||||
|     Attributes | ||||
|     ----------- | ||||
|     user: :class:`User` | ||||
|         The user you have the relationship with. | ||||
|     type: :class:`RelationshipType` | ||||
|         The type of relationship you have. | ||||
|     """ | ||||
|  | ||||
|     __slots__ = ('type', 'user', '_state') | ||||
|  | ||||
|     def __init__(self, *, state, data): | ||||
|         self._state = state | ||||
|         self.type = try_enum(RelationshipType, data['type']) | ||||
|         self.user = state.store_user(data['user']) | ||||
|  | ||||
|     def __repr__(self): | ||||
|         return '<Relationship user={0.user!r} type={0.type!r}>'.format(self) | ||||
|  | ||||
|     @utils.deprecated() | ||||
|     async def delete(self): | ||||
|         """|coro| | ||||
|  | ||||
|         Deletes the relationship. | ||||
|  | ||||
|         .. deprecated:: 1.7 | ||||
|  | ||||
|         Raises | ||||
|         ------ | ||||
|         HTTPException | ||||
|             Deleting the relationship failed. | ||||
|         """ | ||||
|  | ||||
|         await self._state.http.remove_relationship(self.user.id) | ||||
|  | ||||
|     @utils.deprecated() | ||||
|     async def accept(self): | ||||
|         """|coro| | ||||
|  | ||||
|         Accepts the relationship request. e.g. accepting a | ||||
|         friend request. | ||||
|  | ||||
|         .. deprecated:: 1.7 | ||||
|  | ||||
|         Raises | ||||
|         ------- | ||||
|         HTTPException | ||||
|             Accepting the relationship failed. | ||||
|         """ | ||||
|  | ||||
|         await self._state.http.add_relationship(self.user.id) | ||||
| @@ -317,7 +317,7 @@ class AutoShardedClient(Client): | ||||
|  | ||||
|     def _get_state(self, **options): | ||||
|         return AutoShardedConnectionState(dispatch=self.dispatch, | ||||
|                                           handlers=self._handlers, syncer=self._syncer, | ||||
|                                           handlers=self._handlers, | ||||
|                                           hooks=self._hooks, http=self.http, loop=self.loop, **options) | ||||
|  | ||||
|     @property | ||||
|   | ||||
							
								
								
									
										122
									
								
								discord/state.py
									
									
									
									
									
								
							
							
						
						
									
										122
									
								
								discord/state.py
									
									
									
									
									
								
							| @@ -42,7 +42,6 @@ from .emoji import Emoji | ||||
| from .mentions import AllowedMentions | ||||
| from .partial_emoji import PartialEmoji | ||||
| from .message import Message | ||||
| from .relationship import Relationship | ||||
| from .channel import * | ||||
| from .raw_models import * | ||||
| from .member import Member | ||||
| @@ -102,7 +101,7 @@ async def logging_coroutine(coroutine, *, info): | ||||
|         log.exception('Exception occurred during %s', info) | ||||
|  | ||||
| class ConnectionState: | ||||
|     def __init__(self, *, dispatch, handlers, hooks, syncer, http, loop, **options): | ||||
|     def __init__(self, *, dispatch, handlers, hooks, http, loop, **options): | ||||
|         self.loop = loop | ||||
|         self.http = http | ||||
|         self.max_messages = options.get('max_messages', 1000) | ||||
| @@ -110,8 +109,6 @@ class ConnectionState: | ||||
|             self.max_messages = 1000 | ||||
|  | ||||
|         self.dispatch = dispatch | ||||
|         self.syncer = syncer | ||||
|         self.is_bot = None | ||||
|         self.handlers = handlers | ||||
|         self.hooks = hooks | ||||
|         self.shard_count = None | ||||
| @@ -196,7 +193,6 @@ class ConnectionState: | ||||
|         self.user = None | ||||
|         self._users = weakref.WeakValueDictionary() | ||||
|         self._emojis = {} | ||||
|         self._calls = {} | ||||
|         self._guilds = {} | ||||
|         self._voice_clients = {} | ||||
|  | ||||
| @@ -338,7 +334,7 @@ class ConnectionState: | ||||
|         channel_id = channel.id | ||||
|         self._private_channels[channel_id] = channel | ||||
|  | ||||
|         if self.is_bot and len(self._private_channels) > 128: | ||||
|         if len(self._private_channels) > 128: | ||||
|             _, to_remove = self._private_channels.popitem(last=False) | ||||
|             if isinstance(to_remove, DMChannel): | ||||
|                 self._private_channels_by_user.pop(to_remove.recipient.id, None) | ||||
| @@ -403,36 +399,34 @@ class ConnectionState: | ||||
|  | ||||
|     async def _delay_ready(self): | ||||
|         try: | ||||
|             # only real bots wait for GUILD_CREATE streaming | ||||
|             if self.is_bot: | ||||
|                 states = [] | ||||
|                 while True: | ||||
|                     # this snippet of code is basically waiting N seconds | ||||
|                     # until the last GUILD_CREATE was sent | ||||
|                     try: | ||||
|                         guild = await asyncio.wait_for(self._ready_state.get(), timeout=self.guild_ready_timeout) | ||||
|                     except asyncio.TimeoutError: | ||||
|                         break | ||||
|             states = [] | ||||
|             while True: | ||||
|                 # this snippet of code is basically waiting N seconds | ||||
|                 # until the last GUILD_CREATE was sent | ||||
|                 try: | ||||
|                     guild = await asyncio.wait_for(self._ready_state.get(), timeout=self.guild_ready_timeout) | ||||
|                 except asyncio.TimeoutError: | ||||
|                     break | ||||
|                 else: | ||||
|                     if self._guild_needs_chunking(guild): | ||||
|                         future = await self.chunk_guild(guild, wait=False) | ||||
|                         states.append((guild, future)) | ||||
|                     else: | ||||
|                         if self._guild_needs_chunking(guild): | ||||
|                             future = await self.chunk_guild(guild, wait=False) | ||||
|                             states.append((guild, future)) | ||||
|                         if guild.unavailable is False: | ||||
|                             self.dispatch('guild_available', guild) | ||||
|                         else: | ||||
|                             if guild.unavailable is False: | ||||
|                                 self.dispatch('guild_available', guild) | ||||
|                             else: | ||||
|                                 self.dispatch('guild_join', guild) | ||||
|                             self.dispatch('guild_join', guild) | ||||
|  | ||||
|                 for guild, future in states: | ||||
|                     try: | ||||
|                         await asyncio.wait_for(future, timeout=5.0) | ||||
|                     except asyncio.TimeoutError: | ||||
|                         log.warning('Shard ID %s timed out waiting for chunks for guild_id %s.', guild.shard_id, guild.id) | ||||
|             for guild, future in states: | ||||
|                 try: | ||||
|                     await asyncio.wait_for(future, timeout=5.0) | ||||
|                 except asyncio.TimeoutError: | ||||
|                     log.warning('Shard ID %s timed out waiting for chunks for guild_id %s.', guild.shard_id, guild.id) | ||||
|  | ||||
|                     if guild.unavailable is False: | ||||
|                         self.dispatch('guild_available', guild) | ||||
|                     else: | ||||
|                         self.dispatch('guild_join', guild) | ||||
|                 if guild.unavailable is False: | ||||
|                     self.dispatch('guild_available', guild) | ||||
|                 else: | ||||
|                     self.dispatch('guild_join', guild) | ||||
|  | ||||
|             # remove the state | ||||
|             try: | ||||
| @@ -440,10 +434,6 @@ class ConnectionState: | ||||
|             except AttributeError: | ||||
|                 pass # already been deleted somehow | ||||
|  | ||||
|             # call GUILD_SYNC after we're done chunking | ||||
|             if not self.is_bot: | ||||
|                 log.info('Requesting GUILD_SYNC for %s guilds', len(self.guilds)) | ||||
|                 await self.syncer([s.id for s in self.guilds]) | ||||
|         except asyncio.CancelledError: | ||||
|             pass | ||||
|         else: | ||||
| @@ -465,18 +455,6 @@ class ConnectionState: | ||||
|         for guild_data in data['guilds']: | ||||
|             self._add_guild_from_data(guild_data) | ||||
|  | ||||
|         for relationship in data.get('relationships', []): | ||||
|             try: | ||||
|                 r_id = int(relationship['id']) | ||||
|             except KeyError: | ||||
|                 continue | ||||
|             else: | ||||
|                 user._relationships[r_id] = Relationship(state=self, data=relationship) | ||||
|  | ||||
|         for pm in data.get('private_channels', []): | ||||
|             factory, _ = _channel_factory(pm['type']) | ||||
|             self._add_private_channel(factory(me=user, data=pm, state=self)) | ||||
|  | ||||
|         self.dispatch('connect') | ||||
|         self._ready_task = asyncio.ensure_future(self._delay_ready(), loop=self.loop) | ||||
|  | ||||
| @@ -722,22 +700,6 @@ class ConnectionState: | ||||
|         else: | ||||
|             self.dispatch('guild_channel_pins_update', channel, last_pin) | ||||
|  | ||||
|     def parse_channel_recipient_add(self, data): | ||||
|         channel = self._get_private_channel(int(data['channel_id'])) | ||||
|         user = self.store_user(data['user']) | ||||
|         channel.recipients.append(user) | ||||
|         self.dispatch('group_join', channel, user) | ||||
|  | ||||
|     def parse_channel_recipient_remove(self, data): | ||||
|         channel = self._get_private_channel(int(data['channel_id'])) | ||||
|         user = self.store_user(data['user']) | ||||
|         try: | ||||
|             channel.recipients.remove(user) | ||||
|         except ValueError: | ||||
|             pass | ||||
|         else: | ||||
|             self.dispatch('group_remove', channel, user) | ||||
|  | ||||
|     def parse_guild_member_add(self, data): | ||||
|         guild = self._get_guild(int(data['guild_id'])) | ||||
|         if guild is None: | ||||
| @@ -875,10 +837,6 @@ class ConnectionState: | ||||
|         else: | ||||
|             self.dispatch('guild_join', guild) | ||||
|  | ||||
|     def parse_guild_sync(self, data): | ||||
|         guild = self._get_guild(int(data['id'])) | ||||
|         guild._sync(data) | ||||
|  | ||||
|     def parse_guild_update(self, data): | ||||
|         guild = self._get_guild(int(data['id'])) | ||||
|         if guild is not None: | ||||
| @@ -1024,11 +982,6 @@ class ConnectionState: | ||||
|                 self.dispatch('voice_state_update', member, before, after) | ||||
|             else: | ||||
|                 log.debug('VOICE_STATE_UPDATE referencing an unknown member ID: %s. Discarding.', data['user_id']) | ||||
|         else: | ||||
|             # in here we're either at private or group calls | ||||
|             call = self._calls.get(channel_id) | ||||
|             if call is not None: | ||||
|                 call._update_voice_state(data) | ||||
|  | ||||
|     def parse_voice_server_update(self, data): | ||||
|         try: | ||||
| @@ -1062,25 +1015,6 @@ class ConnectionState: | ||||
|                 timestamp = datetime.datetime.utcfromtimestamp(data.get('timestamp')) | ||||
|                 self.dispatch('typing', channel, member, timestamp) | ||||
|  | ||||
|     def parse_relationship_add(self, data): | ||||
|         key = int(data['id']) | ||||
|         old = self.user.get_relationship(key) | ||||
|         new = Relationship(state=self, data=data) | ||||
|         self.user._relationships[key] = new | ||||
|         if old is not None: | ||||
|             self.dispatch('relationship_update', old, new) | ||||
|         else: | ||||
|             self.dispatch('relationship_add', new) | ||||
|  | ||||
|     def parse_relationship_remove(self, data): | ||||
|         key = int(data['id']) | ||||
|         try: | ||||
|             old = self.user._relationships.pop(key) | ||||
|         except KeyError: | ||||
|             pass | ||||
|         else: | ||||
|             self.dispatch('relationship_remove', old) | ||||
|  | ||||
|     def _get_reaction_user(self, channel, user_id): | ||||
|         if isinstance(channel, TextChannel): | ||||
|             return channel.guild.get_member(user_id) | ||||
| @@ -1224,10 +1158,6 @@ class AutoShardedConnectionState(ConnectionState): | ||||
|         if self._messages: | ||||
|             self._update_message_references() | ||||
|  | ||||
|         for pm in data.get('private_channels', []): | ||||
|             factory, _ = _channel_factory(pm['type']) | ||||
|             self._add_private_channel(factory(me=user, data=pm, state=self)) | ||||
|  | ||||
|         self.dispatch('connect') | ||||
|         self.dispatch('shard_connect', data['__shard_id__']) | ||||
|  | ||||
|   | ||||
| @@ -41,10 +41,6 @@ class _PartialTemplateState: | ||||
|         self.__state = state | ||||
|         self.http = _FriendlyHttpAttributeErrorHelper() | ||||
|  | ||||
|     @property | ||||
|     def is_bot(self): | ||||
|         return self.__state.is_bot | ||||
|  | ||||
|     @property | ||||
|     def shard_count(self): | ||||
|         return self.__state.shard_count | ||||
| @@ -125,7 +121,7 @@ class Template: | ||||
|             source_serialised['id'] = id | ||||
|             state = _PartialTemplateState(state=self._state) | ||||
|             guild = Guild(data=source_serialised, state=state) | ||||
|          | ||||
|  | ||||
|         self.source_guild = guild | ||||
|  | ||||
|     def __repr__(self): | ||||
|   | ||||
							
								
								
									
										558
									
								
								discord/user.py
									
									
									
									
									
								
							
							
						
						
									
										558
									
								
								discord/user.py
									
									
									
									
									
								
							| @@ -22,62 +22,12 @@ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||||
| DEALINGS IN THE SOFTWARE. | ||||
| """ | ||||
|  | ||||
| from collections import namedtuple | ||||
|  | ||||
| import discord.abc | ||||
| from .flags import PublicUserFlags | ||||
| from .utils import snowflake_time, _bytes_to_base64_data, parse_time | ||||
| from .enums import DefaultAvatar, RelationshipType, UserFlags, HypeSquadHouse, PremiumType, try_enum | ||||
| from .errors import ClientException | ||||
| from .utils import snowflake_time, _bytes_to_base64_data | ||||
| from .enums import DefaultAvatar, try_enum | ||||
| from .colour import Colour | ||||
| from .asset import Asset | ||||
| from .utils import deprecated | ||||
|  | ||||
| class Profile(namedtuple('Profile', 'flags user mutual_guilds connected_accounts premium_since')): | ||||
|     __slots__ = () | ||||
|  | ||||
|     @property | ||||
|     def nitro(self): | ||||
|         return self.premium_since is not None | ||||
|  | ||||
|     premium = nitro | ||||
|  | ||||
|     def _has_flag(self, o): | ||||
|         v = o.value | ||||
|         return (self.flags & v) == v | ||||
|  | ||||
|     @property | ||||
|     def staff(self): | ||||
|         return self._has_flag(UserFlags.staff) | ||||
|  | ||||
|     @property | ||||
|     def partner(self): | ||||
|         return self._has_flag(UserFlags.partner) | ||||
|  | ||||
|     @property | ||||
|     def bug_hunter(self): | ||||
|         return self._has_flag(UserFlags.bug_hunter) | ||||
|  | ||||
|     @property | ||||
|     def early_supporter(self): | ||||
|         return self._has_flag(UserFlags.early_supporter) | ||||
|  | ||||
|     @property | ||||
|     def hypesquad(self): | ||||
|         return self._has_flag(UserFlags.hypesquad) | ||||
|  | ||||
|     @property | ||||
|     def hypesquad_houses(self): | ||||
|         flags = (UserFlags.hypesquad_bravery, UserFlags.hypesquad_brilliance, UserFlags.hypesquad_balance) | ||||
|         return [house for house, flag in zip(HypeSquadHouse, flags) if self._has_flag(flag)] | ||||
|  | ||||
|     @property | ||||
|     def team_user(self): | ||||
|         return self._has_flag(UserFlags.team_user) | ||||
|  | ||||
|     @property | ||||
|     def system(self): | ||||
|         return self._has_flag(UserFlags.system) | ||||
|  | ||||
| _BaseUser = discord.abc.User | ||||
|  | ||||
| @@ -314,32 +264,16 @@ class ClientUser(BaseUser): | ||||
|  | ||||
|     verified: :class:`bool` | ||||
|         Specifies if the user is a verified account. | ||||
|     email: Optional[:class:`str`] | ||||
|         The email the user used when registering. | ||||
|  | ||||
|         .. deprecated:: 1.7 | ||||
|  | ||||
|     locale: Optional[:class:`str`] | ||||
|         The IETF language tag used to identify the language the user is using. | ||||
|     mfa_enabled: :class:`bool` | ||||
|         Specifies if the user has MFA turned on and working. | ||||
|     premium: :class:`bool` | ||||
|         Specifies if the user is a premium user (e.g. has Discord Nitro). | ||||
|  | ||||
|         .. deprecated:: 1.7 | ||||
|  | ||||
|     premium_type: Optional[:class:`PremiumType`] | ||||
|         Specifies the type of premium a user has (e.g. Nitro or Nitro Classic). Could be None if the user is not premium. | ||||
|  | ||||
|         .. deprecated:: 1.7 | ||||
|     """ | ||||
|     __slots__ = BaseUser.__slots__ + \ | ||||
|                 ('email', 'locale', '_flags', 'verified', 'mfa_enabled', | ||||
|                  'premium', 'premium_type', '_relationships', '__weakref__') | ||||
|                 ('locale', '_flags', 'verified', 'mfa_enabled', '__weakref__') | ||||
|  | ||||
|     def __init__(self, *, state, data): | ||||
|         super().__init__(state=state, data=data) | ||||
|         self._relationships = {} | ||||
|  | ||||
|     def __repr__(self): | ||||
|         return '<ClientUser id={0.id} name={0.name!r} discriminator={0.discriminator!r}' \ | ||||
| @@ -349,83 +283,16 @@ class ClientUser(BaseUser): | ||||
|         super()._update(data) | ||||
|         # There's actually an Optional[str] phone field as well but I won't use it | ||||
|         self.verified = data.get('verified', False) | ||||
|         self.email = data.get('email') | ||||
|         self.locale = data.get('locale') | ||||
|         self._flags = data.get('flags', 0) | ||||
|         self.mfa_enabled = data.get('mfa_enabled', False) | ||||
|         self.premium = data.get('premium', False) | ||||
|         self.premium_type = try_enum(PremiumType, data.get('premium_type', None)) | ||||
|  | ||||
|     @deprecated() | ||||
|     def get_relationship(self, user_id): | ||||
|         """Retrieves the :class:`Relationship` if applicable. | ||||
|  | ||||
|         .. deprecated:: 1.7 | ||||
|  | ||||
|         .. note:: | ||||
|  | ||||
|             This can only be used by non-bot accounts. | ||||
|  | ||||
|         Parameters | ||||
|         ----------- | ||||
|         user_id: :class:`int` | ||||
|             The user ID to check if we have a relationship with them. | ||||
|  | ||||
|         Returns | ||||
|         -------- | ||||
|         Optional[:class:`Relationship`] | ||||
|             The relationship if available or ``None``. | ||||
|         """ | ||||
|         return self._relationships.get(user_id) | ||||
|  | ||||
|     @property | ||||
|     def relationships(self): | ||||
|         """List[:class:`User`]: Returns all the relationships that the user has. | ||||
|  | ||||
|         .. deprecated:: 1.7 | ||||
|  | ||||
|         .. note:: | ||||
|  | ||||
|             This can only be used by non-bot accounts. | ||||
|         """ | ||||
|         return list(self._relationships.values()) | ||||
|  | ||||
|     @property | ||||
|     def friends(self): | ||||
|         r"""List[:class:`User`]: Returns all the users that the user is friends with. | ||||
|  | ||||
|         .. deprecated:: 1.7 | ||||
|  | ||||
|         .. note:: | ||||
|  | ||||
|             This can only be used by non-bot accounts. | ||||
|         """ | ||||
|         return [r.user for r in self._relationships.values() if r.type is RelationshipType.friend] | ||||
|  | ||||
|     @property | ||||
|     def blocked(self): | ||||
|         r"""List[:class:`User`]: Returns all the users that the user has blocked. | ||||
|  | ||||
|         .. deprecated:: 1.7 | ||||
|  | ||||
|         .. note:: | ||||
|  | ||||
|             This can only be used by non-bot accounts. | ||||
|         """ | ||||
|         return [r.user for r in self._relationships.values() if r.type is RelationshipType.blocked] | ||||
|  | ||||
|     async def edit(self, **fields): | ||||
|     async def edit(self, *, username=None, avatar=None): | ||||
|         """|coro| | ||||
|  | ||||
|         Edits the current profile of the client. | ||||
|  | ||||
|         If a bot account is used then a password field is optional, | ||||
|         otherwise it is required. | ||||
|  | ||||
|         .. warning:: | ||||
|  | ||||
|             The user account-only fields are deprecated. | ||||
|  | ||||
|         .. note:: | ||||
|  | ||||
|             To upload an avatar, a :term:`py:bytes-like object` must be passed in that | ||||
| @@ -437,19 +304,6 @@ class ClientUser(BaseUser): | ||||
|  | ||||
|         Parameters | ||||
|         ----------- | ||||
|         password: :class:`str` | ||||
|             The current password for the client's account. | ||||
|             Only applicable to user accounts. | ||||
|         new_password: :class:`str` | ||||
|             The new password you wish to change to. | ||||
|             Only applicable to user accounts. | ||||
|         email: :class:`str` | ||||
|             The new email you wish to change to. | ||||
|             Only applicable to user accounts. | ||||
|         house: Optional[:class:`HypeSquadHouse`] | ||||
|             The hypesquad house you wish to change to. | ||||
|             Could be ``None`` to leave the current house. | ||||
|             Only applicable to user accounts. | ||||
|         username: :class:`str` | ||||
|             The new username you wish to change to. | ||||
|         avatar: :class:`bytes` | ||||
| @@ -462,218 +316,14 @@ class ClientUser(BaseUser): | ||||
|             Editing your profile failed. | ||||
|         InvalidArgument | ||||
|             Wrong image format passed for ``avatar``. | ||||
|         ClientException | ||||
|             Password is required for non-bot accounts. | ||||
|             House field was not a HypeSquadHouse. | ||||
|         """ | ||||
|  | ||||
|         try: | ||||
|             avatar_bytes = fields['avatar'] | ||||
|         except KeyError: | ||||
|             avatar = self.avatar | ||||
|         else: | ||||
|             if avatar_bytes is not None: | ||||
|                 avatar = _bytes_to_base64_data(avatar_bytes) | ||||
|             else: | ||||
|                 avatar = None | ||||
|  | ||||
|         not_bot_account = not self.bot | ||||
|         password = fields.get('password') | ||||
|         if not_bot_account and password is None: | ||||
|             raise ClientException('Password is required for non-bot accounts.') | ||||
|  | ||||
|         args = { | ||||
|             'password': password, | ||||
|             'username': fields.get('username', self.name), | ||||
|             'avatar': avatar | ||||
|         } | ||||
|  | ||||
|         if not_bot_account: | ||||
|             args['email'] = fields.get('email', self.email) | ||||
|  | ||||
|             if 'new_password' in fields: | ||||
|                 args['new_password'] = fields['new_password'] | ||||
|  | ||||
|         http = self._state.http | ||||
|  | ||||
|         if 'house' in fields: | ||||
|             house = fields['house'] | ||||
|             if house is None: | ||||
|                 await http.leave_hypesquad_house() | ||||
|             elif not isinstance(house, HypeSquadHouse): | ||||
|                 raise ClientException('`house` parameter was not a HypeSquadHouse') | ||||
|             else: | ||||
|                 value = house.value | ||||
|  | ||||
|             await http.change_hypesquad_house(value) | ||||
|  | ||||
|         data = await http.edit_profile(**args) | ||||
|         if not_bot_account: | ||||
|             self.email = data['email'] | ||||
|             try: | ||||
|                 http._token(data['token'], bot=False) | ||||
|             except KeyError: | ||||
|                 pass | ||||
|         if avatar is not None: | ||||
|             avatar = _bytes_to_base64_data(avatar) | ||||
|  | ||||
|         data = await self._state.http.edit_profile(username=username, avatar=avatar) | ||||
|         self._update(data) | ||||
|  | ||||
|     @deprecated() | ||||
|     async def create_group(self, *recipients): | ||||
|         r"""|coro| | ||||
|  | ||||
|         Creates a group direct message with the recipients | ||||
|         provided. These recipients must be have a relationship | ||||
|         of type :attr:`RelationshipType.friend`. | ||||
|  | ||||
|         .. deprecated:: 1.7 | ||||
|  | ||||
|         .. note:: | ||||
|  | ||||
|             This can only be used by non-bot accounts. | ||||
|  | ||||
|         Parameters | ||||
|         ----------- | ||||
|         \*recipients: :class:`User` | ||||
|             An argument :class:`list` of :class:`User` to have in | ||||
|             your group. | ||||
|  | ||||
|         Raises | ||||
|         ------- | ||||
|         HTTPException | ||||
|             Failed to create the group direct message. | ||||
|         ClientException | ||||
|             Attempted to create a group with only one recipient. | ||||
|             This does not include yourself. | ||||
|  | ||||
|         Returns | ||||
|         ------- | ||||
|         :class:`GroupChannel` | ||||
|             The new group channel. | ||||
|         """ | ||||
|  | ||||
|         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 = await self._state.http.start_group(self.id, users) | ||||
|         return GroupChannel(me=self, data=data, state=self._state) | ||||
|  | ||||
|     @deprecated() | ||||
|     async def edit_settings(self, **kwargs): | ||||
|         """|coro| | ||||
|  | ||||
|         Edits the client user's settings. | ||||
|  | ||||
|         .. deprecated:: 1.7 | ||||
|  | ||||
|         .. note:: | ||||
|  | ||||
|             This can only be used by non-bot accounts. | ||||
|  | ||||
|         Parameters | ||||
|         ------- | ||||
|         afk_timeout: :class:`int` | ||||
|             How long (in seconds) the user needs to be AFK until Discord | ||||
|             sends push notifications to your mobile device. | ||||
|         animate_emojis: :class:`bool` | ||||
|             Whether or not to animate emojis in the chat. | ||||
|         convert_emoticons: :class:`bool` | ||||
|             Whether or not to automatically convert emoticons into emojis. | ||||
|             e.g. :-) -> 😃 | ||||
|         default_guilds_restricted: :class:`bool` | ||||
|             Whether or not to automatically disable DMs between you and | ||||
|             members of new guilds you join. | ||||
|         detect_platform_accounts: :class:`bool` | ||||
|             Whether or not to automatically detect accounts from services | ||||
|             like Steam and Blizzard when you open the Discord client. | ||||
|         developer_mode: :class:`bool` | ||||
|             Whether or not to enable developer mode. | ||||
|         disable_games_tab: :class:`bool` | ||||
|             Whether or not to disable the showing of the Games tab. | ||||
|         enable_tts_command: :class:`bool` | ||||
|             Whether or not to allow tts messages to be played/sent. | ||||
|         explicit_content_filter: :class:`UserContentFilter` | ||||
|             The filter for explicit content in all messages. | ||||
|         friend_source_flags: :class:`FriendFlags` | ||||
|             Who can add you as a friend. | ||||
|         gif_auto_play: :class:`bool` | ||||
|             Whether or not to automatically play gifs that are in the chat. | ||||
|         guild_positions: List[:class:`abc.Snowflake`] | ||||
|             A list of guilds in order of the guild/guild icons that are on | ||||
|             the left hand side of the UI. | ||||
|         inline_attachment_media: :class:`bool` | ||||
|             Whether or not to display attachments when they are uploaded in chat. | ||||
|         inline_embed_media: :class:`bool` | ||||
|             Whether or not to display videos and images from links posted in chat. | ||||
|         locale: :class:`str` | ||||
|             The :rfc:`3066` language identifier of the locale to use for the language | ||||
|             of the Discord client. | ||||
|         message_display_compact: :class:`bool` | ||||
|             Whether or not to use the compact Discord display mode. | ||||
|         render_embeds: :class:`bool` | ||||
|             Whether or not to render embeds that are sent in the chat. | ||||
|         render_reactions: :class:`bool` | ||||
|             Whether or not to render reactions that are added to messages. | ||||
|         restricted_guilds: List[:class:`abc.Snowflake`] | ||||
|             A list of guilds that you will not receive DMs from. | ||||
|         show_current_game: :class:`bool` | ||||
|             Whether or not to display the game that you are currently playing. | ||||
|         status: :class:`Status` | ||||
|             The clients status that is shown to others. | ||||
|         theme: :class:`Theme` | ||||
|             The theme of the Discord UI. | ||||
|         timezone_offset: :class:`int` | ||||
|             The timezone offset to use. | ||||
|  | ||||
|         Raises | ||||
|         ------- | ||||
|         HTTPException | ||||
|             Editing the settings failed. | ||||
|         Forbidden | ||||
|             The client is a bot user and not a user account. | ||||
|  | ||||
|         Returns | ||||
|         ------- | ||||
|         :class:`dict` | ||||
|             The client user's updated settings. | ||||
|         """ | ||||
|         payload = {} | ||||
|  | ||||
|         content_filter = kwargs.pop('explicit_content_filter', None) | ||||
|         if content_filter: | ||||
|             payload.update({'explicit_content_filter': content_filter.value}) | ||||
|  | ||||
|         friend_flags = kwargs.pop('friend_source_flags', None) | ||||
|         if friend_flags: | ||||
|             dicts = [{}, {'mutual_guilds': True}, {'mutual_friends': True}, | ||||
|             {'mutual_guilds': True, 'mutual_friends': True}, {'all': True}] | ||||
|             payload.update({'friend_source_flags': dicts[friend_flags.value]}) | ||||
|  | ||||
|         guild_positions = kwargs.pop('guild_positions', None) | ||||
|         if guild_positions: | ||||
|             guild_positions = [str(x.id) for x in guild_positions] | ||||
|             payload.update({'guild_positions': guild_positions}) | ||||
|  | ||||
|         restricted_guilds = kwargs.pop('restricted_guilds', None) | ||||
|         if restricted_guilds: | ||||
|             restricted_guilds = [str(x.id) for x in restricted_guilds] | ||||
|             payload.update({'restricted_guilds': restricted_guilds}) | ||||
|  | ||||
|         status = kwargs.pop('status', None) | ||||
|         if status: | ||||
|             payload.update({'status': status.value}) | ||||
|  | ||||
|         theme = kwargs.pop('theme', None) | ||||
|         if theme: | ||||
|             payload.update({'theme': theme.value}) | ||||
|  | ||||
|         payload.update(kwargs) | ||||
|  | ||||
|         data = await self._state.http.edit_settings(**payload) | ||||
|         return data | ||||
|  | ||||
| class User(BaseUser, discord.abc.Messageable): | ||||
|     """Represents a Discord user. | ||||
|  | ||||
| @@ -761,197 +411,3 @@ class User(BaseUser, discord.abc.Messageable): | ||||
|         state = self._state | ||||
|         data = await state.http.start_private_message(self.id) | ||||
|         return state.add_dm_channel(data) | ||||
|  | ||||
|     @property | ||||
|     def relationship(self): | ||||
|         """Optional[:class:`Relationship`]: Returns the :class:`Relationship` with this user if applicable, ``None`` otherwise. | ||||
|  | ||||
|         .. deprecated:: 1.7 | ||||
|  | ||||
|         .. note:: | ||||
|  | ||||
|             This can only be used by non-bot accounts. | ||||
|         """ | ||||
|         return self._state.user.get_relationship(self.id) | ||||
|  | ||||
|     @deprecated() | ||||
|     async def mutual_friends(self): | ||||
|         """|coro| | ||||
|  | ||||
|         Gets all mutual friends of this user. | ||||
|  | ||||
|         .. deprecated:: 1.7 | ||||
|  | ||||
|         .. note:: | ||||
|  | ||||
|             This can only be used by non-bot accounts. | ||||
|  | ||||
|         Raises | ||||
|         ------- | ||||
|         Forbidden | ||||
|             Not allowed to get mutual friends of this user. | ||||
|         HTTPException | ||||
|             Getting mutual friends failed. | ||||
|  | ||||
|         Returns | ||||
|         ------- | ||||
|         List[:class:`User`] | ||||
|             The users that are mutual friends. | ||||
|         """ | ||||
|         state = self._state | ||||
|         mutuals = await state.http.get_mutual_friends(self.id) | ||||
|         return [User(state=state, data=friend) for friend in mutuals] | ||||
|  | ||||
|     @deprecated() | ||||
|     def is_friend(self): | ||||
|         """:class:`bool`: Checks if the user is your friend. | ||||
|  | ||||
|         .. deprecated:: 1.7 | ||||
|  | ||||
|         .. note:: | ||||
|  | ||||
|             This can only be used by non-bot accounts. | ||||
|         """ | ||||
|         r = self.relationship | ||||
|         if r is None: | ||||
|             return False | ||||
|         return r.type is RelationshipType.friend | ||||
|  | ||||
|     @deprecated() | ||||
|     def is_blocked(self): | ||||
|         """:class:`bool`: Checks if the user is blocked. | ||||
|  | ||||
|         .. deprecated:: 1.7 | ||||
|  | ||||
|         .. note:: | ||||
|  | ||||
|             This can only be used by non-bot accounts. | ||||
|         """ | ||||
|         r = self.relationship | ||||
|         if r is None: | ||||
|             return False | ||||
|         return r.type is RelationshipType.blocked | ||||
|  | ||||
|     @deprecated() | ||||
|     async def block(self): | ||||
|         """|coro| | ||||
|  | ||||
|         Blocks the user. | ||||
|  | ||||
|         .. deprecated:: 1.7 | ||||
|  | ||||
|         .. note:: | ||||
|  | ||||
|             This can only be used by non-bot accounts. | ||||
|  | ||||
|         Raises | ||||
|         ------- | ||||
|         Forbidden | ||||
|             Not allowed to block this user. | ||||
|         HTTPException | ||||
|             Blocking the user failed. | ||||
|         """ | ||||
|  | ||||
|         await self._state.http.add_relationship(self.id, type=RelationshipType.blocked.value) | ||||
|  | ||||
|     @deprecated() | ||||
|     async def unblock(self): | ||||
|         """|coro| | ||||
|  | ||||
|         Unblocks the user. | ||||
|  | ||||
|         .. deprecated:: 1.7 | ||||
|  | ||||
|         .. note:: | ||||
|  | ||||
|             This can only be used by non-bot accounts. | ||||
|  | ||||
|         Raises | ||||
|         ------- | ||||
|         Forbidden | ||||
|             Not allowed to unblock this user. | ||||
|         HTTPException | ||||
|             Unblocking the user failed. | ||||
|         """ | ||||
|         await self._state.http.remove_relationship(self.id) | ||||
|  | ||||
|     @deprecated() | ||||
|     async def remove_friend(self): | ||||
|         """|coro| | ||||
|  | ||||
|         Removes the user as a friend. | ||||
|  | ||||
|         .. deprecated:: 1.7 | ||||
|  | ||||
|         .. note:: | ||||
|  | ||||
|             This can only be used by non-bot accounts. | ||||
|  | ||||
|         Raises | ||||
|         ------- | ||||
|         Forbidden | ||||
|             Not allowed to remove this user as a friend. | ||||
|         HTTPException | ||||
|             Removing the user as a friend failed. | ||||
|         """ | ||||
|         await self._state.http.remove_relationship(self.id) | ||||
|  | ||||
|     @deprecated() | ||||
|     async def send_friend_request(self): | ||||
|         """|coro| | ||||
|  | ||||
|         Sends the user a friend request. | ||||
|  | ||||
|         .. deprecated:: 1.7 | ||||
|  | ||||
|         .. note:: | ||||
|  | ||||
|             This can only be used by non-bot accounts. | ||||
|  | ||||
|         Raises | ||||
|         ------- | ||||
|         Forbidden | ||||
|             Not allowed to send a friend request to the user. | ||||
|         HTTPException | ||||
|             Sending the friend request failed. | ||||
|         """ | ||||
|         await self._state.http.send_friend_request(username=self.name, discriminator=self.discriminator) | ||||
|  | ||||
|     @deprecated() | ||||
|     async def profile(self): | ||||
|         """|coro| | ||||
|  | ||||
|         Gets the user's profile. | ||||
|  | ||||
|         .. deprecated:: 1.7 | ||||
|  | ||||
|         .. note:: | ||||
|  | ||||
|             This can only be used by non-bot accounts. | ||||
|  | ||||
|         Raises | ||||
|         ------- | ||||
|         Forbidden | ||||
|             Not allowed to fetch profiles. | ||||
|         HTTPException | ||||
|             Fetching the profile failed. | ||||
|  | ||||
|         Returns | ||||
|         -------- | ||||
|         :class:`Profile` | ||||
|             The profile of the user. | ||||
|         """ | ||||
|  | ||||
|         state = self._state | ||||
|         data = await state.http.get_user_profile(self.id) | ||||
|  | ||||
|         def transform(d): | ||||
|             return state._get_guild(int(d['id'])) | ||||
|  | ||||
|         since = data.get('premium_since') | ||||
|         mutual_guilds = list(filter(None, map(transform, data.get('mutual_guilds', [])))) | ||||
|         return Profile(flags=data['user'].get('flags', 0), | ||||
|                        premium_since=parse_time(since), | ||||
|                        mutual_guilds=mutual_guilds, | ||||
|                        user=self, | ||||
|                        connected_accounts=data['connected_accounts']) | ||||
|   | ||||
| @@ -403,10 +403,6 @@ class _PartialWebhookState: | ||||
|     def store_user(self, data): | ||||
|         return BaseUser(state=self, data=data) | ||||
|  | ||||
|     @property | ||||
|     def is_bot(self): | ||||
|         return True | ||||
|  | ||||
|     @property | ||||
|     def http(self): | ||||
|         if self.parent is not None: | ||||
|   | ||||
							
								
								
									
										235
									
								
								docs/api.rst
									
									
									
									
									
								
							
							
						
						
									
										235
									
								
								docs/api.rst
									
									
									
									
									
								
							| @@ -897,29 +897,6 @@ to handle it, which defaults to print a traceback and ignoring the exception. | ||||
|     :param user: The user that joined or left. | ||||
|     :type user: :class:`User` | ||||
|  | ||||
| .. function:: on_relationship_add(relationship) | ||||
|               on_relationship_remove(relationship) | ||||
|  | ||||
|     Called when a :class:`Relationship` is added or removed from the | ||||
|     :class:`ClientUser`. | ||||
|  | ||||
|     .. deprecated:: 1.7 | ||||
|  | ||||
|     :param relationship: The relationship that was added or removed. | ||||
|     :type relationship: :class:`Relationship` | ||||
|  | ||||
| .. function:: on_relationship_update(before, after) | ||||
|  | ||||
|     Called when a :class:`Relationship` is updated, e.g. when you | ||||
|     block a friend or a friendship is accepted. | ||||
|  | ||||
|     .. deprecated:: 1.7 | ||||
|  | ||||
|     :param before: The previous relationship status. | ||||
|     :type before: :class:`Relationship` | ||||
|     :param after: The updated relationship status. | ||||
|     :type after: :class:`Relationship` | ||||
|  | ||||
| .. _discord-api-utils: | ||||
|  | ||||
| Utility Functions | ||||
| @@ -945,97 +922,6 @@ Utility Functions | ||||
|  | ||||
| .. autofunction:: discord.utils.sleep_until | ||||
|  | ||||
| Profile | ||||
| --------- | ||||
|  | ||||
| .. class:: Profile | ||||
|  | ||||
|     A namedtuple representing a user's Discord public profile. | ||||
|  | ||||
|     .. deprecated:: 1.7 | ||||
|  | ||||
|     .. attribute:: user | ||||
|  | ||||
|         The :class:`User` the profile belongs to. | ||||
|  | ||||
|         :type: :class:`User` | ||||
|     .. attribute:: premium | ||||
|  | ||||
|         A boolean indicating if the user has premium (i.e. Discord Nitro). | ||||
|  | ||||
|         :type: :class:`bool` | ||||
|     .. attribute:: nitro | ||||
|  | ||||
|         An alias for :attr:`premium`. | ||||
|     .. attribute:: premium_since | ||||
|  | ||||
|         A naive UTC datetime indicating how long the user has been premium since. | ||||
|         This could be ``None`` if not applicable. | ||||
|  | ||||
|         :type: :class:`datetime.datetime` | ||||
|     .. attribute:: staff | ||||
|  | ||||
|         A boolean indicating if the user is Discord Staff. | ||||
|  | ||||
|         :type: :class:`bool` | ||||
|     .. attribute:: partner | ||||
|  | ||||
|         A boolean indicating if the user is a Discord Partner. | ||||
|  | ||||
|         :type: :class:`bool` | ||||
|     .. attribute:: bug_hunter | ||||
|  | ||||
|         A boolean indicating if the user is a Bug Hunter. | ||||
|  | ||||
|         :type: :class:`bool` | ||||
|     .. attribute:: early_supporter | ||||
|  | ||||
|         A boolean indicating if the user has had premium before 10 October, 2018. | ||||
|  | ||||
|         :type: :class:`bool` | ||||
|     .. attribute:: hypesquad | ||||
|  | ||||
|         A boolean indicating if the user is in Discord HypeSquad. | ||||
|  | ||||
|         :type: :class:`bool` | ||||
|     .. attribute:: hypesquad_houses | ||||
|  | ||||
|         A list of :class:`HypeSquadHouse` that the user is in. | ||||
|  | ||||
|         :type: List[:class:`HypeSquadHouse`] | ||||
|     .. attribute:: team_user | ||||
|  | ||||
|         A boolean indicating if the user is in part of a team. | ||||
|  | ||||
|         .. versionadded:: 1.3 | ||||
|  | ||||
|         :type: :class:`bool` | ||||
|  | ||||
|     .. attribute:: system | ||||
|  | ||||
|         A boolean indicating if the user is officially part of the Discord urgent message system. | ||||
|  | ||||
|         .. versionadded:: 1.3 | ||||
|  | ||||
|         :type: :class:`bool` | ||||
|  | ||||
|     .. attribute:: mutual_guilds | ||||
|  | ||||
|         A list of :class:`Guild` that the :class:`ClientUser` shares with this | ||||
|         user. | ||||
|  | ||||
|         :type: List[:class:`Guild`] | ||||
|  | ||||
|     .. attribute:: connected_accounts | ||||
|  | ||||
|         A list of dict objects indicating the accounts the user has connected. | ||||
|  | ||||
|         An example entry can be seen below: :: | ||||
|  | ||||
|             {"type": "twitch", "id": "92473777", "name": "discordapp"} | ||||
|  | ||||
|         :type: List[Dict[:class:`str`, :class:`str`]] | ||||
|  | ||||
| .. _discord-api-enums: | ||||
|  | ||||
| Enumerations | ||||
| @@ -1940,127 +1826,6 @@ of :class:`enum.Enum`. | ||||
|  | ||||
|         The action is the update of something. | ||||
|  | ||||
| .. class:: RelationshipType | ||||
|  | ||||
|     Specifies the type of :class:`Relationship`. | ||||
|  | ||||
|     .. deprecated:: 1.7 | ||||
|  | ||||
|     .. note:: | ||||
|  | ||||
|         This only applies to users, *not* bots. | ||||
|  | ||||
|     .. attribute:: friend | ||||
|  | ||||
|         You are friends with this user. | ||||
|  | ||||
|     .. attribute:: blocked | ||||
|  | ||||
|         You have blocked this user. | ||||
|  | ||||
|     .. attribute:: incoming_request | ||||
|  | ||||
|         The user has sent you a friend request. | ||||
|  | ||||
|     .. attribute:: outgoing_request | ||||
|  | ||||
|         You have sent a friend request to this user. | ||||
|  | ||||
|  | ||||
| .. class:: UserContentFilter | ||||
|  | ||||
|     Represents the options found in ``Settings > Privacy & Safety > Safe Direct Messaging`` | ||||
|     in the Discord client. | ||||
|  | ||||
|     .. deprecated:: 1.7 | ||||
|  | ||||
|     .. note:: | ||||
|  | ||||
|         This only applies to users, *not* bots. | ||||
|  | ||||
|     .. attribute:: all_messages | ||||
|  | ||||
|         Scan all direct messages from everyone. | ||||
|  | ||||
|     .. attribute:: friends | ||||
|  | ||||
|         Scan all direct messages that aren't from friends. | ||||
|  | ||||
|     .. attribute:: disabled | ||||
|  | ||||
|         Don't scan any direct messages. | ||||
|  | ||||
|  | ||||
| .. class:: FriendFlags | ||||
|  | ||||
|     Represents the options found in ``Settings > Privacy & Safety > Who Can Add You As A Friend`` | ||||
|     in the Discord client. | ||||
|  | ||||
|     .. deprecated:: 1.7 | ||||
|  | ||||
|     .. note:: | ||||
|  | ||||
|         This only applies to users, *not* bots. | ||||
|  | ||||
|     .. attribute:: noone | ||||
|  | ||||
|         This allows no-one to add you as a friend. | ||||
|  | ||||
|     .. attribute:: mutual_guilds | ||||
|  | ||||
|         This allows guild members to add you as a friend. | ||||
|  | ||||
|     .. attribute:: mutual_friends | ||||
|  | ||||
|         This allows friends of friends to add you as a friend. | ||||
|  | ||||
|     .. attribute:: guild_and_friends | ||||
|  | ||||
|         This is a superset of :attr:`mutual_guilds` and :attr:`mutual_friends`. | ||||
|  | ||||
|     .. attribute:: everyone | ||||
|  | ||||
|         This allows everyone to add you as a friend. | ||||
|  | ||||
|  | ||||
| .. class:: PremiumType | ||||
|  | ||||
|     Represents the user's Discord Nitro subscription type. | ||||
|  | ||||
|     .. deprecated:: 1.7 | ||||
|  | ||||
|     .. note:: | ||||
|  | ||||
|         This only applies to users, *not* bots. | ||||
|  | ||||
|     .. attribute:: nitro | ||||
|  | ||||
|         Represents the Discord Nitro with Nitro-exclusive games. | ||||
|  | ||||
|     .. attribute:: nitro_classic | ||||
|  | ||||
|         Represents the Discord Nitro with no Nitro-exclusive games. | ||||
|  | ||||
|  | ||||
| .. class:: Theme | ||||
|  | ||||
|     Represents the theme synced across all Discord clients. | ||||
|  | ||||
|     .. deprecated:: 1.7 | ||||
|  | ||||
|     .. note:: | ||||
|  | ||||
|         This only applies to users, *not* bots. | ||||
|  | ||||
|     .. attribute:: light | ||||
|  | ||||
|         Represents the Light theme on Discord. | ||||
|  | ||||
|     .. attribute:: dark | ||||
|  | ||||
|         Represents the Dark theme on Discord. | ||||
|  | ||||
|  | ||||
| .. class:: TeamMembershipState | ||||
|  | ||||
|     Represents the membership state of a team member retrieved through :func:`Bot.application_info`. | ||||
|   | ||||
		Reference in New Issue
	
	Block a user