aboutsummaryrefslogtreecommitdiff
path: root/discord/channel.py
diff options
context:
space:
mode:
authorRapptz <[email protected]>2016-12-30 22:56:47 -0500
committerRapptz <[email protected]>2017-01-03 09:52:08 -0500
commit67099798319d59fa5dc06f43802cc411ac33426f (patch)
tree58f0af35dad9e46d0846838f6d32f34087dd3771 /discord/channel.py
parentRemove chunks of the voice code to redesign later. (diff)
downloaddiscord.py-67099798319d59fa5dc06f43802cc411ac33426f.tar.xz
discord.py-67099798319d59fa5dc06f43802cc411ac33426f.zip
Move GuildChannel over to abc module.
Diffstat (limited to 'discord/channel.py')
-rw-r--r--discord/channel.py267
1 files changed, 2 insertions, 265 deletions
diff --git a/discord/channel.py b/discord/channel.py
index 75d801ef..80ecdaab 100644
--- a/discord/channel.py
+++ b/discord/channel.py
@@ -25,7 +25,6 @@ DEALINGS IN THE SOFTWARE.
from .permissions import Permissions, PermissionOverwrite
from .enums import ChannelType, try_enum
-from collections import namedtuple
from .mixins import Hashable
from .role import Role
from .user import User
@@ -39,269 +38,7 @@ import asyncio
__all__ = ('TextChannel', 'VoiceChannel', 'DMChannel', 'GroupChannel', '_channel_factory')
-Overwrites = namedtuple('Overwrites', 'id allow deny type')
-
-class CommonGuildChannel(Hashable):
- __slots__ = ()
-
- def __str__(self):
- return self.name
-
- @asyncio.coroutine
- def _move(self, position):
- if position < 0:
- raise InvalidArgument('Channel position cannot be less than 0.')
-
- http = self._state.http
- url = '{0}/{1.guild.id}/channels'.format(http.GUILDS, self)
- channels = [c for c in self.guild.channels if isinstance(c, type(self))]
-
- if position >= len(channels):
- raise InvalidArgument('Channel position cannot be greater than {}'.format(len(channels) - 1))
-
- channels.sort(key=lambda c: c.position)
-
- try:
- # remove ourselves from the channel list
- channels.remove(self)
- except ValueError:
- # not there somehow lol
- return
- else:
- # add ourselves at our designated position
- channels.insert(position, self)
-
- payload = [{'id': c.id, 'position': index } for index, c in enumerate(channels)]
- yield from http.patch(url, json=payload, bucket='move_channel')
-
- def _fill_overwrites(self, data):
- self._overwrites = []
- everyone_index = 0
- everyone_id = self.guild.id
-
- for index, overridden in enumerate(data.get('permission_overwrites', [])):
- overridden_id = int(overridden.pop('id'))
- self._overwrites.append(Overwrites(id=overridden_id, **overridden))
-
- if overridden['type'] == 'member':
- continue
-
- if overridden_id == everyone_id:
- # the @everyone role is not guaranteed to be the first one
- # in the list of permission overwrites, however the permission
- # resolution code kind of requires that it is the first one in
- # the list since it is special. So we need the index so we can
- # swap it to be the first one.
- everyone_index = index
-
- # do the swap
- tmp = self._overwrites
- if tmp:
- tmp[everyone_index], tmp[0] = tmp[0], tmp[everyone_index]
-
- @property
- def changed_roles(self):
- """Returns a list of :class:`Roles` that have been overridden from
- their default values in the :attr:`Guild.roles` attribute."""
- ret = []
- for overwrite in filter(lambda o: o.type == 'role', self._overwrites):
- role = discord.utils.get(self.guild.roles, id=overwrite.id)
- if role is None:
- continue
-
- role = copy.copy(role)
- role.permissions.handle_overwrite(overwrite.allow, overwrite.deny)
- ret.append(role)
- return ret
-
- @property
- def is_default(self):
- """bool : Indicates if this is the default channel for the :class:`Guild` it belongs to."""
- return self.guild.id == self.id
-
- @property
- def mention(self):
- """str : The string that allows you to mention the channel."""
- return '<#{0.id}>'.format(self)
-
- @property
- def created_at(self):
- """Returns the channel's creation time in UTC."""
- return discord.utils.snowflake_time(self.id)
-
- def overwrites_for(self, obj):
- """Returns the channel-specific overwrites for a member or a role.
-
- Parameters
- -----------
- obj
- The :class:`Role` or :class:`Member` or :class:`Object` denoting
- whose overwrite to get.
-
- Returns
- ---------
- :class:`PermissionOverwrite`
- The permission overwrites for this object.
- """
-
- if isinstance(obj, Member):
- predicate = lambda p: p.type == 'member'
- elif isinstance(obj, Role):
- predicate = lambda p: p.type == 'role'
- else:
- predicate = lambda p: True
-
- for overwrite in filter(predicate, self._overwrites):
- if overwrite.id == obj.id:
- allow = Permissions(overwrite.allow)
- deny = Permissions(overwrite.deny)
- return PermissionOverwrite.from_pair(allow, deny)
-
- return PermissionOverwrite()
-
- @property
- def overwrites(self):
- """Returns all of the channel's overwrites.
-
- This is returned as a list of two-element tuples containing the target,
- which can be either a :class:`Role` or a :class:`Member` and the overwrite
- as the second element as a :class:`PermissionOverwrite`.
-
- Returns
- --------
- List[Tuple[Union[:class:`Role`, :class:`Member`], :class:`PermissionOverwrite`]]:
- The channel's permission overwrites.
- """
- ret = []
- for ow in self._permission_overwrites:
- allow = Permissions(ow.allow)
- deny = Permissions(ow.deny)
- overwrite = PermissionOverwrite.from_pair(allow, deny)
-
- if ow.type == 'role':
- # accidentally quadratic
- target = discord.utils.find(lambda r: r.id == ow.id, self.server.roles)
- elif ow.type == 'member':
- target = self.server.get_member(ow.id)
-
- ret.append((target, overwrite))
- return ret
-
- def permissions_for(self, member):
- """Handles permission resolution for the current :class:`Member`.
-
- This function takes into consideration the following cases:
-
- - Guild owner
- - Guild roles
- - Channel overrides
- - Member overrides
- - Whether the channel is the default channel.
-
- Parameters
- ----------
- member : :class:`Member`
- The member to resolve permissions for.
-
- Returns
- -------
- :class:`Permissions`
- The resolved permissions for the member.
- """
-
- # The current cases can be explained as:
- # Guild owner get all permissions -- no questions asked. Otherwise...
- # The @everyone role gets the first application.
- # After that, the applied roles that the user has in the channel
- # (or otherwise) are then OR'd together.
- # After the role permissions are resolved, the member permissions
- # have to take into effect.
- # After all that is done.. you have to do the following:
-
- # If manage permissions is True, then all permissions are set to
- # True. If the channel is the default channel then everyone gets
- # read permissions regardless.
-
- # The operation first takes into consideration the denied
- # and then the allowed.
-
- if member.id == self.guild.owner.id:
- return Permissions.all()
-
- default = self.guild.default_role
- base = Permissions(default.permissions.value)
-
- # Apply guild roles that the member has.
- for role in member.roles:
- base.value |= role.permissions.value
-
- # Guild-wide Administrator -> True for everything
- # Bypass all channel-specific overrides
- if base.administrator:
- return Permissions.all()
-
- member_role_ids = set(map(lambda r: r.id, member.roles))
- denies = 0
- allows = 0
-
- # Apply channel specific role permission overwrites
- for overwrite in self._overwrites:
- if overwrite.type == 'role' and overwrite.id in member_role_ids:
- denies |= overwrite.deny
- allows |= overwrite.allow
-
- base.handle_overwrite(allow=allows, deny=denies)
-
- # Apply member specific permission overwrites
- for overwrite in self._overwrites:
- if overwrite.type == 'member' and overwrite.id == member.id:
- base.handle_overwrite(allow=overwrite.allow, deny=overwrite.deny)
- break
-
- # default channels can always be read
- if self.is_default:
- base.read_messages = True
-
- # if you can't send a message in a channel then you can't have certain
- # permissions as well
- if not base.send_messages:
- base.send_tts_messages = False
- base.mention_everyone = False
- base.embed_links = False
- base.attach_files = False
-
- # if you can't read a channel then you have no permissions there
- if not base.read_messages:
- denied = Permissions.all_channel()
- base.value &= ~denied.value
-
- # text channels do not have voice related permissions
- if isinstance(self, TextChannel):
- denied = Permissions.voice()
- base.value &= ~denied.value
-
- return base
-
- @asyncio.coroutine
- def delete(self):
- """|coro|
-
- Deletes the channel.
-
- You must have Manage Channel permission to use this.
-
- Raises
- -------
- Forbidden
- You do not have proper permissions to delete the channel.
- NotFound
- The channel was not found or was already deleted.
- HTTPException
- Deleting the channel failed.
- """
- yield from self._state.http.delete_channel(self.id)
-
-class TextChannel(discord.abc.MessageChannel, CommonGuildChannel):
+class TextChannel(discord.abc.MessageChannel, discord.abc.GuildChannel, Hashable):
"""Represents a Discord guild text channel.
Supported Operations:
@@ -393,7 +130,7 @@ class TextChannel(discord.abc.MessageChannel, CommonGuildChannel):
data = yield from self._state.http.edit_channel(self.id, **options)
self._update(self.guild, data)
-class VoiceChannel(CommonGuildChannel):
+class VoiceChannel(discord.abc.GuildChannel, Hashable):
"""Represents a Discord guild voice channel.
Supported Operations: