fix conflicts

This commit is contained in:
iDutchy
2021-05-02 21:05:05 -05:00
84 changed files with 2683 additions and 706 deletions

View File

@@ -3,7 +3,7 @@
"""
The MIT License (MIT)
Copyright (c) 2015-2020 Rapptz
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"),
@@ -24,6 +24,8 @@ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
"""
import datetime
import inspect
import itertools
import sys
from operator import attrgetter
@@ -31,6 +33,7 @@ from operator import attrgetter
import discord.abc
from . import utils
from .errors import ClientException
from .user import BaseUser, User
from .activity import create_activity
from .permissions import Permissions
@@ -58,15 +61,32 @@ class VoiceState:
self_video: :class:`bool`
Indicates if the user is currently broadcasting video.
suppress: :class:`bool`
Indicates if the user is suppressed from speaking.
Only applies to stage channels.
.. versionadded:: 1.7
requested_to_speak_at: Optional[:class:`datetime.datetime`]
A datetime object that specifies the date and time in UTC that the member
requested to speak. It will be ``None`` if they are not requesting to speak
anymore or have been accepted to speak.
Only applicable to stage channels.
.. versionadded:: 1.7
afk: :class:`bool`
Indicates if the user is currently in the AFK channel in the guild.
channel: Optional[:class:`VoiceChannel`]
channel: Optional[Union[:class:`VoiceChannel`, :class:`StageChannel`]]
The voice channel that the user is currently connected to. ``None`` if the user
is not currently in a voice channel.
"""
__slots__ = ('session_id', 'deaf', 'mute', 'self_mute',
'self_stream', 'self_video', 'self_deaf', 'afk', 'channel')
'self_stream', 'self_video', 'self_deaf', 'afk', 'channel',
'requested_to_speak_at', 'suppress')
def __init__(self, *, data, channel=None):
self.session_id = data.get('session_id')
@@ -80,10 +100,20 @@ class VoiceState:
self.afk = data.get('suppress', False)
self.mute = data.get('mute', False)
self.deaf = data.get('deaf', False)
self.suppress = data.get('suppress', False)
self.requested_to_speak_at = utils.parse_time(data.get('request_to_speak_timestamp'))
self.channel = channel
def __repr__(self):
return '<VoiceState self_mute={0.self_mute} self_deaf={0.self_deaf} self_stream={0.self_stream} channel={0.channel!r}>'.format(self)
attrs = [
('self_mute', self.self_mute),
('self_deaf', self.self_deaf),
('self_stream', self.self_stream),
('suppress', self.suppress),
('requested_to_speak_at', self.requested_to_speak_at),
('channel', self.channel)
]
return '<%s %s>' % (self.__class__.__name__, ' '.join('%s=%r' % t for t in attrs))
def flatten_user(cls):
for attr, value in itertools.chain(BaseUser.__dict__.items(), User.__dict__.items()):
@@ -106,14 +136,19 @@ def flatten_user(cls):
# It probably breaks something in Sphinx.
# probably a member function by now
def generate_function(x):
def general(self, *args, **kwargs):
return getattr(self._user, x)(*args, **kwargs)
# We want sphinx to properly show coroutine functions as coroutines
if inspect.iscoroutinefunction(value):
async def general(self, *args, **kwargs):
return await getattr(self._user, x)(*args, **kwargs)
else:
def general(self, *args, **kwargs):
return getattr(self._user, x)(*args, **kwargs)
general.__name__ = x
return general
func = generate_function(attr)
func.__doc__ = value.__doc__
func = utils.copy_doc(value)(func)
setattr(cls, attr, func)
return cls
@@ -153,6 +188,13 @@ class Member(discord.abc.Messageable, _BaseUser):
If the member left and rejoined the guild, this will be the latest date. In certain cases, this can be ``None``.
activities: Tuple[Union[:class:`BaseActivity`, :class:`Spotify`]]
The activities that the user is currently doing.
.. note::
Due to a Discord API limitation, a user's Spotify activity may not appear
if they are listening to a song with a title longer
than 128 characters. See :issue:`1738` for more information.
guild: :class:`Guild`
The guild that the member belongs to.
nick: Optional[:class:`str`]
@@ -293,12 +335,12 @@ class Member(discord.abc.Messageable, _BaseUser):
def _update_inner_user(self, user):
u = self._user
original = (u.name, u.avatar, u.discriminator)
original = (u.name, u.avatar, u.discriminator, u._public_flags)
# These keys seem to always be available
modified = (user['username'], user['avatar'], user['discriminator'])
modified = (user['username'], user['avatar'], user['discriminator'], user.get('public_flags', 0))
if original != modified:
to_return = User._copy(self._user)
u.name, u.avatar, u.discriminator = modified
u.name, u.avatar, u.discriminator, u._public_flags = modified
# Signal to dispatch on_user_update
return to_return, u
@@ -401,13 +443,19 @@ class Member(discord.abc.Messageable, _BaseUser):
if they have a guild specific nickname then that
is returned instead.
"""
return self.nick if self.nick is not None else self.name
return self.nick or self.name
@property
def activity(self):
"""Union[:class:`BaseActivity`, :class:`Spotify`]: Returns the primary
activity the user is currently doing. Could be ``None`` if no activity is being done.
.. note::
Due to a Discord API limitation, this may be ``None`` if
the user is listening to a song on Spotify with a title longer
than 128 characters. See :issue:`1738` for more information.
.. note::
A user may have multiple activities, these can be accessed under :attr:`activities`.
@@ -434,11 +482,7 @@ class Member(discord.abc.Messageable, _BaseUser):
if self._user.mentioned_in(message):
return True
for role in message.role_mentions:
if self._roles.has(role.id):
return True
return False
return any(self._roles.has(role.id) for role in message.role_mentions)
def permissions_in(self, channel):
"""An alias for :meth:`abc.GuildChannel.permissions_for`.
@@ -560,6 +604,11 @@ class Member(discord.abc.Messageable, _BaseUser):
Indicates if the member should be guild muted or un-muted.
deafen: :class:`bool`
Indicates if the member should be guild deafened or un-deafened.
suppress: :class:`bool`
Indicates if the member should be suppressed in stage channels.
.. versionadded:: 1.7
roles: Optional[List[:class:`Role`]]
The member's new list of roles. This *replaces* the roles.
voice_channel: Optional[:class:`VoiceChannel`]
@@ -577,6 +626,7 @@ class Member(discord.abc.Messageable, _BaseUser):
"""
http = self._state.http
guild_id = self.guild.id
me = self._state.self_id == self.id
payload = {}
try:
@@ -585,8 +635,8 @@ class Member(discord.abc.Messageable, _BaseUser):
# nick not present so...
pass
else:
nick = nick if nick else ''
if self._state.self_id == self.id:
nick = nick or ''
if me:
await http.change_my_nickname(guild_id, nick, reason=reason)
else:
payload['nick'] = nick
@@ -599,6 +649,23 @@ class Member(discord.abc.Messageable, _BaseUser):
if mute is not None:
payload['mute'] = mute
suppress = fields.get('suppress')
if suppress is not None:
voice_state_payload = {
'channel_id': self.voice.channel.id,
'suppress': suppress,
}
if suppress or self.bot:
voice_state_payload['request_to_speak_timestamp'] = None
if me:
await http.edit_my_voice_state(guild_id, voice_state_payload)
else:
if not suppress:
voice_state_payload['request_to_speak_timestamp'] = datetime.datetime.utcnow().isoformat()
await http.edit_voice_state(guild_id, self.id, voice_state_payload)
try:
vc = fields['voice_channel']
except KeyError:
@@ -613,10 +680,43 @@ class Member(discord.abc.Messageable, _BaseUser):
else:
payload['roles'] = tuple(r.id for r in roles)
await http.edit_member(guild_id, self.id, reason=reason, **payload)
if payload:
await http.edit_member(guild_id, self.id, reason=reason, **payload)
# TODO: wait for WS event for modify-in-place behaviour
async def request_to_speak(self):
"""|coro|
Request to speak in the connected channel.
Only applies to stage channels.
.. note::
Requesting members that are not the client is equivalent
to :attr:`.edit` providing ``suppress`` as ``False``.
.. versionadded:: 1.7
Raises
-------
Forbidden
You do not have the proper permissions to the action requested.
HTTPException
The operation failed.
"""
payload = {
'channel_id': self.voice.channel.id,
'request_to_speak_timestamp': datetime.datetime.utcnow().isoformat(),
}
if self._state.self_id != self.id:
payload['suppress'] = False
await self._state.http.edit_voice_state(self.guild.id, self.id, payload)
else:
await self._state.http.edit_my_voice_state(self.guild.id, payload)
async def move_to(self, channel, *, reason=None):
"""|coro|