conflict fixes
This commit is contained in:
@@ -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|
|
||||
|
||||
|
||||
Reference in New Issue
Block a user