aboutsummaryrefslogtreecommitdiff
path: root/discord/member.py
diff options
context:
space:
mode:
Diffstat (limited to 'discord/member.py')
-rw-r--r--discord/member.py95
1 files changed, 90 insertions, 5 deletions
diff --git a/discord/member.py b/discord/member.py
index a72e9945..d0e969bd 100644
--- a/discord/member.py
+++ b/discord/member.py
@@ -24,6 +24,7 @@ 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
@@ -32,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
@@ -59,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')
@@ -81,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()):
@@ -559,6 +588,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`]
@@ -576,6 +610,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,7 +620,7 @@ class Member(discord.abc.Messageable, _BaseUser):
pass
else:
nick = nick or ''
- if self._state.self_id == self.id:
+ if me:
await http.change_my_nickname(guild_id, nick, reason=reason)
else:
payload['nick'] = nick
@@ -598,6 +633,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:
@@ -612,10 +664,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|