conflict fixes

This commit is contained in:
iDutchy
2021-04-07 18:27:34 -05:00
94 changed files with 4512 additions and 3018 deletions

View File

@@ -1,9 +1,7 @@
# -*- coding: utf-8 -*-
"""
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 +22,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 +31,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
@@ -38,6 +39,11 @@ from .enums import Status, try_enum
from .colour import Colour
from .object import Object
__all__ = (
'VoiceState',
'Member',
)
class VoiceState:
"""Represents a Discord user's voice state.
@@ -58,15 +64,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`]
An aware 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 +103,21 @@ 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)
]
inner = ' '.join('%s=%r' % t for t in attrs)
return f'<{self.__class__.__name__} {inner}>'
def flatten_user(cls):
for attr, value in itertools.chain(BaseUser.__dict__.items(), User.__dict__.items()):
@@ -99,21 +133,26 @@ def flatten_user(cls):
# slotted members are implemented as member_descriptors in Type.__dict__
if not hasattr(value, '__annotations__'):
getter = attrgetter('_user.' + attr)
setattr(cls, attr, property(getter, doc='Equivalent to :attr:`User.%s`' % attr))
setattr(cls, attr, property(getter, doc=f'Equivalent to :attr:`User.{attr}`'))
else:
# Technically, this can also use attrgetter
# However I'm not sure how I feel about "functions" returning properties
# 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
@@ -149,7 +188,7 @@ class Member(discord.abc.Messageable, _BaseUser):
Attributes
----------
joined_at: Optional[:class:`datetime.datetime`]
A datetime object that specifies the date and time in UTC that the member joined the guild.
An aware datetime object that specifies the date and time in UTC that the member joined the guild.
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.
@@ -162,7 +201,7 @@ class Member(discord.abc.Messageable, _BaseUser):
.. versionadded:: 1.6
premium_since: Optional[:class:`datetime.datetime`]
A datetime object that specifies the date and time in UTC when the member used their
An aware datetime object that specifies the date and time in UTC when the member used their
Nitro boost on the guild, if available. This could be ``None``.
"""
@@ -190,8 +229,8 @@ class Member(discord.abc.Messageable, _BaseUser):
return self.id
def __repr__(self):
return '<Member id={1.id} name={1.name!r} discriminator={1.discriminator!r}' \
' bot={1.bot} nick={0.nick!r} guild={0.guild!r}>'.format(self, self._user)
return f'<Member id={self._user.id} name={self._user.name!r} discriminator={self._user.discriminator!r}' \
f' bot={self._user.bot} nick={self.nick!r} guild={self.guild!r}>'
def __eq__(self, other):
return isinstance(other, _BaseUser) and other.id == self.id
@@ -293,12 +332,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
@@ -390,8 +429,8 @@ class Member(discord.abc.Messageable, _BaseUser):
def mention(self):
""":class:`str`: Returns a string that allows you to mention the member."""
if self.nick:
return '<@!%s>' % self.id
return '<@%s>' % self.id
return f'<@!{self._user.id}>'
return f'<@{self._user.id}>'
@property
def display_name(self):
@@ -401,7 +440,7 @@ 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):
@@ -434,11 +473,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 +595,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 +617,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 +626,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 +640,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 +671,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|