class MessageEmbed(SlottedModel): """ Message embed object. Attributes ---------- title : str Title of the embed. type : str Type of the embed. description : str Description of the embed. url : str URL of the embed. """ title = Field(text) type = Field(str, default='rich') description = Field(text) url = Field(text) timestamp = Field(lazy_datetime) color = Field(int) footer = Field(MessageEmbedFooter) image = Field(MessageEmbedImage) thumbnail = Field(MessageEmbedThumbnail) video = Field(MessageEmbedVideo) author = Field(MessageEmbedAuthor) fields = ListField(MessageEmbedField)
class GuildEmoji(Emoji): """ An emoji object. Attributes ---------- id : snowflake The ID of this emoji. name : str The name of this emoji. require_colons : bool Whether this emoji requires colons to use. managed : bool Whether this emoji is managed by an integration. roles : list(snowflake) Roles this emoji is attached to. """ id = Field(snowflake) guild_id = Field(snowflake) name = Field(text) require_colons = Field(bool) managed = Field(bool) roles = ListField(snowflake) @property def url(self): return 'https://discordapp.com/api/emojis/{}.png'.format(self.id) @cached_property def guild(self): return self.client.state.guilds.get(self.guild_id)
class WatcherChangeParserResult(GatewayEvent): app_id = Field(str) branch_name = Field(str) branch_version = Field(str) parser = Field(str) # name of parser result = ListField(str) # absolute path to some files def __str__(self): return "[{}][{}][{}]".format(self.app_id, self.parser, self.result)
class GuildPreview(SlottedModel): id = Field(int) name = Field(str) icon = Field(str) splash = Field(str) discovery_splash = Field(str) emojis = AutoDictField(GuildEmoji, 'id') features = ListField(str) approximate_member_count = Field(int) approximate_presence_count = Field(int) description = Field(str)
class GuildEmojisUpdate(GatewayEvent): """ Sent when a guild's emojis are updated. Attributes ----- guild_id : snowflake The ID of the guild the emojis are being updated in. emojis : list[:class:`disco.types.guild.Emoji`] The new set of emojis for the guild """ guild_id = Field(snowflake) emojis = ListField(Emoji)
class MessageDeleteBulk(GatewayEvent): """ Sent when multiple messages are deleted from a channel. Attributes ----- channel_id : snowflake The channel the messages are being deleted in. ids : list[snowflake] List of messages being deleted in the channel. """ channel_id = Field(snowflake) ids = ListField(snowflake)
class GuildMembersChunk(GatewayEvent): """ Sent in response to a member's chunk request. Attributes ----- guild_id : snowflake The ID of the guild this member chunk is for. members : list[:class:`disco.types.guild.GuildMember`] The chunk of members. not_found : list[snowflake] An array of invalid requested guild members. presences : list[:class:`disco.types.user.Presence`] An array of requested member presence states. """ guild_id = Field(snowflake) members = ListField(GuildMember) not_found = ListField(snowflake) presences = ListField(Presence) @property def guild(self): return self.client.state.guilds.get(self.guild_id)
class Ready(GatewayEvent): """ Sent after the initial gateway handshake is complete. Contains data required for bootstrapping the client's states. Attributes ----- version : int The gateway version. session_id : str The session ID. user : :class:`disco.types.user.User` The user object for the authed account. guilds : list[:class:`disco.types.guild.Guild` All guilds this account is a member of. These are shallow guild objects. private_channels list[:class:`disco.types.channel.Channel`] All private channels (DMs) open for this account. """ version = Field(int, alias='v') session_id = Field(str) user = Field(User) guilds = ListField(Guild) private_channels = ListField(Guild)
class GuildEmoji(Emoji): """ An emoji object. Attributes ---------- id : snowflake The ID of this emoji. name : str The name of this emoji. require_colons : bool Whether this emoji requires colons to use. managed : bool Whether this emoji is managed by an integration. roles : list(snowflake) Roles this emoji is attached to. animated : bool Whether this emoji is animated. """ id = Field(snowflake) guild_id = Field(snowflake) name = Field(text) require_colons = Field(bool) managed = Field(bool) roles = ListField(snowflake) animated = Field(bool) def __str__(self): return u'<{}:{}:{}>'.format('a' if self.animated else '', self.name, self.id) def update(self, **kwargs): return self.client.api.guilds_emojis_modify(self.guild_id, self.id, **kwargs) def delete(self, **kwargs): return self.client.api.guilds_emojis_delete(self.guild_id, self.id, **kwargs) @property def url(self): return 'https://media.discordapp.net/emojis/{}.{}'.format( self.id, 'gif' if self.animated else 'png') @cached_property def guild(self): return self.client.state.guilds.get(self.guild_id)
class GuildMembersChunk(GatewayEvent): """ Sent in response to a member's chunk request. Attributes ----- guild_id : snowflake The ID of the guild this member chunk is for. members : list[:class:`disco.types.guild.GuildMember`] The chunk of members. """ guild_id = Field(snowflake) members = ListField(GuildMember) @property def guild(self): return self.client.state.guilds.get(self.guild_id)
class AuditLogEntry(SlottedModel): id = Field(snowflake) guild_id = Field(snowflake) user_id = Field(snowflake) target_id = Field(snowflake) action_type = Field(enum(AuditLogActionTypes)) changes = ListField(AuditLogObjectChange) options = DictField(text, text) reason = Field(text) _cached_target = Field(None) @classmethod def create(cls, client, users, webhooks, data, **kwargs): self = super(SlottedModel, cls).create(client, data, **kwargs) if self.action_type in MEMBER_ACTIONS: self._cached_target = users[self.target_id] elif self.action_type in WEBHOOK_ACTIONS: self._cached_target = webhooks[self.target_id] return self @cached_property def guild(self): return self.client.state.guilds.get(self.guild_id) @cached_property def user(self): return self.client.state.users.get(self.user_id) @cached_property def target(self): if self.action_type in GUILD_ACTIONS: return self.guild elif self.action_type in CHANNEL_ACTIONS: return self.guild.channels.get(self.target_id) elif self.action_type in MEMBER_ACTIONS: return self._cached_target or self.state.users.get(self.target_id) elif self.action_type in ROLE_ACTIONS: return self.guild.roles.get(self.target_id) elif self.action_type in WEBHOOK_ACTIONS: return self._cached_target elif self.action_type in EMOJI_ACTIONS: return self.guild.emojis.get(self.target_id)
class MessageEmbed(SlottedModel): """ Message embed object. Attributes ---------- title : str Title of the embed. type : str Type of the embed. description : str Description of the embed. url : str URL of the embed. """ title = Field(text) type = Field(str, default='rich') description = Field(text) url = Field(text) timestamp = Field(datetime) color = Field(int) footer = Field(MessageEmbedFooter) image = Field(MessageEmbedImage) thumbnail = Field(MessageEmbedThumbnail) video = Field(MessageEmbedVideo) author = Field(MessageEmbedAuthor) fields = ListField(MessageEmbedField) def set_footer(self, *args, **kwargs): self.footer = MessageEmbedFooter(*args, **kwargs) def set_image(self, *args, **kwargs): self.image = MessageEmbedImage(*args, **kwargs) def set_thumbnail(self, *args, **kwargs): self.thumbnail = MessageEmbedThumbnail(*args, **kwargs) def set_video(self, *args, **kwargs): self.video = MessageEmbedVideo(*args, **kwargs) def set_author(self, *args, **kwargs): self.author = MessageEmbedAuthor(*args, **kwargs) def add_field(self, *args, **kwargs): self.fields.append(MessageEmbedField(*args, **kwargs))
class PresenceUpdate(GatewayEvent): """ Sent when a user's presence is updated. Attributes ----- presence : :class:`disco.types.user.Presence` The updated presence object. guild_id : snowflake The guild this presence update is for. roles : list[snowflake] List of roles the user from the presence is part of. """ guild_id = Field(snowflake) roles = ListField(snowflake) @property def guild(self): return self.client.state.guilds.get(self.guild_id)
class GuildCreate(GatewayEvent): """ Sent when a guild is joined, or becomes available. Attributes ----- guild : :class:`disco.types.guild.Guild` The guild being created (e.g. joined) unavailable : bool If false, this guild is coming online from a previously unavailable state, and if None, this is a normal guild join event. """ unavailable = Field(bool) presences = ListField(Presence) @property def created(self): """ Shortcut property which is true when we actually joined the guild. """ return self.unavailable is None
class MessageDeleteBulk(GatewayEvent): """ Sent when multiple messages are deleted from a channel. Attributes ----- channel_id : snowflake The channel the messages are being deleted in. ids : list[snowflake] List of messages being deleted in the channel. """ channel_id = Field(snowflake) ids = ListField(snowflake) @property def channel(self): return self.client.state.channels.get(self.channel_id) @property def guild(self): return self.channel.guild
class WebConfig(Model): viewers = ListField(snowflake) editors = ListField(snowflake) admins = ListField(snowflake)
class Party(SlottedModel): id = Field(text) size = ListField(int)
class Presence(SlottedModel): user = Field(User, alias='user', ignore_dump=['presence']) game = Field(Game) status = Field(Status) activities = ListField(Game) client_status = Field(ClientStatus)
class Message(SlottedModel): """ Represents a Message created within a Channel on Discord. Attributes ---------- id : snowflake The ID of this message. channel_id : snowflake The channel ID this message was sent in. type : `MessageType` Type of the message. author : :class:`disco.types.user.User` The author of this message. content : str The unicode contents of this message. nonce : str The nonce of this message. timestamp : datetime When this message was created. edited_timestamp : datetime? When this message was last edited. tts : bool Whether this is a TTS (text-to-speech) message. mention_everyone : bool Whether this message has an @everyone which mentions everyone. pinned : bool Whether this message is pinned in the channel. mentions : dict[snowflake, `User`] Users mentioned within this message. mention_roles : list[snowflake] IDs for roles mentioned within this message. embeds : list[`MessageEmbed`] Embeds for this message. attachments : list[`MessageAttachment`] Attachments for this message. reactions : list[`MessageReaction`] Reactions for this message. """ id = Field(snowflake) channel_id = Field(snowflake) webhook_id = Field(snowflake) type = Field(enum(MessageType)) author = Field(User) content = Field(text) nonce = Field(snowflake) timestamp = Field(datetime) edited_timestamp = Field(datetime) tts = Field(bool) mention_everyone = Field(bool) pinned = Field(bool) mentions = AutoDictField(User, 'id') mention_roles = ListField(snowflake) embeds = ListField(MessageEmbed) attachments = AutoDictField(MessageAttachment, 'id') reactions = ListField(MessageReaction) def __str__(self): return '<Message {} ({})>'.format(self.id, self.channel_id) @cached_property def guild(self): """ Returns ------- `Guild` The guild (if applicable) this message was created in. """ return self.channel.guild @cached_property def member(self): """ Returns ------- `GuildMember` The guild member (if applicable) that sent this message. """ return self.channel.guild.get_member(self.author) @cached_property def channel(self): """ Returns ------- `Channel` The channel this message was created in. """ return self.client.state.channels.get(self.channel_id) def pin(self): """ Pins the message to the channel it was created in. """ self.channel.create_pin(self) def unpin(self): """ Unpins the message from the channel it was created in. """ self.channel.delete_pin(self) def reply(self, *args, **kwargs): """ Reply to this message (see `Channel.send_message`). Returns ------- `Message` The created message object. """ return self.channel.send_message(*args, **kwargs) def edit(self, *args, **kwargs): """ Edit this message. Args ---- content : str The new edited contents of the message. Returns ------- `Message` The edited message object. """ return self.client.api.channels_messages_modify( self.channel_id, self.id, *args, **kwargs) def delete(self): """ Delete this message. Returns ------- `Message` The deleted message object. """ return self.client.api.channels_messages_delete( self.channel_id, self.id) def get_reactors(self, emoji, *args, **kwargs): """ Returns an iterator which paginates the reactors for the given emoji. Returns ------- `Paginator`(`User`) An iterator which handles pagination of reactors. """ if isinstance(emoji, Emoji): emoji = emoji.to_string() return Paginator(self.client.api.channels_messages_reactions_get, 'after', self.channel_id, self.id, emoji, *args, **kwargs) def create_reaction(self, emoji): warnings.warn( 'Message.create_reaction will be deprecated soon, use Message.add_reaction', DeprecationWarning) return self.add_reaction(emoji) def add_reaction(self, emoji): """ Adds a reaction to the message. Parameters ---------- emoji : `Emoji`|str An emoji or string representing an emoji """ if isinstance(emoji, Emoji): emoji = emoji.to_string() self.client.api.channels_messages_reactions_create( self.channel_id, self.id, emoji) def delete_reaction(self, emoji, user=None): """ Deletes a reaction from the message. """ if isinstance(emoji, Emoji): emoji = emoji.to_string() if user: user = to_snowflake(user) self.client.api.channels_messages_reactions_delete( self.channel_id, self.id, emoji, user) def is_mentioned(self, entity): """ Returns ------- bool Whether the give entity was mentioned. """ entity = to_snowflake(entity) return entity in self.mentions or entity in self.mention_roles @cached_property def without_mentions(self, valid_only=False): """ Returns ------- str the message contents with all mentions removed. """ return self.replace_mentions(lambda u: '', lambda r: '', lambda c: '', nonexistant=not valid_only) @cached_property def with_proper_mentions(self): """ Returns ------- str The message with mentions replaced w/ their proper form. """ def replace_user(u): return u'@' + six.text_type(u) def replace_role(r): return u'@' + six.text_type(r) def replace_channel(c): return six.text_type(c) return self.replace_mentions(replace_user, replace_role, replace_channel) def replace_mentions(self, user_replace=None, role_replace=None, channel_replace=None, nonexistant=False): """ Replaces user and role mentions with the result of a given lambda/function. Args ---- user_replace : function A function taking a single argument, the user object mentioned, and returning a valid string. role_replace : function A function taking a single argument, the role ID mentioned, and returning a valid string. Returns ------- str The message contents with all valid mentions replaced. """ def replace(getter, func, match): oid = int(match.group(2)) obj = getter(oid) if obj or nonexistant: return func(obj or oid) or match.group(0) return match.group(0) content = self.content if user_replace: replace_user = functools.partial(replace, self.mentions.get, user_replace) content = re.sub('(<@!?([0-9]+)>)', replace_user, content) if role_replace: replace_role = functools.partial( replace, lambda v: (self.guild and self.guild.roles.get(v)), role_replace) content = re.sub('(<@&([0-9]+)>)', replace_role, content) if channel_replace: replace_channel = functools.partial(replace, self.client.state.channels.get, channel_replace) content = re.sub('(<#([0-9]+)>)', replace_channel, content) return content
class MessageEmbed(SlottedModel): """ Message embed object. Attributes ---------- title : str Title of the embed. type : str Type of the embed. description : str Description of the embed. url : str URL of the embed. timestamp : datetime The timestamp for the embed. color : int The color of the embed. footer : `MessageEmbedFooter` The footer of the embed. thumbnail : `MessageEmbedThumbnail` The thumbnail of the embed. video : `MessageEmbedVideo` The video of the embed. author : `MessageEmbedAuthor` The author of the embed. fields : list[`MessageEmbedField]` The fields of the embed. """ title = Field(text) type = Field(str, default='rich') description = Field(text) url = Field(text) timestamp = Field(datetime) color = Field(int) footer = Field(MessageEmbedFooter) image = Field(MessageEmbedImage) thumbnail = Field(MessageEmbedThumbnail) video = Field(MessageEmbedVideo) author = Field(MessageEmbedAuthor) fields = ListField(MessageEmbedField) def set_footer(self, *args, **kwargs): """ Sets the footer of the embed, see `MessageEmbedFooter`. """ self.footer = MessageEmbedFooter(*args, **kwargs) def set_image(self, *args, **kwargs): """ Sets the image of the embed, see `MessageEmbedImage`. """ self.image = MessageEmbedImage(*args, **kwargs) def set_thumbnail(self, *args, **kwargs): """ Sets the thumbnail of the embed, see `MessageEmbedThumbnail`. """ self.thumbnail = MessageEmbedThumbnail(*args, **kwargs) def set_video(self, *args, **kwargs): """ Sets the video of the embed, see `MessageEmbedVideo`. """ self.video = MessageEmbedVideo(*args, **kwargs) def set_author(self, *args, **kwargs): """ Sets the author of the embed, see `MessageEmbedAuthor`. """ self.author = MessageEmbedAuthor(*args, **kwargs) def add_field(self, *args, **kwargs): """ Adds a new field to the embed, see `MessageEmbedField`. """ self.fields.append(MessageEmbedField(*args, **kwargs))
class Resumed(GatewayEvent): """ Sent after a resume completes. """ trace = ListField(str, alias='_trace')
class GuildMember(SlottedModel): """ A GuildMember object. Attributes ---------- user : :class:`disco.types.user.User` The user object of this member. guild_id : snowflake The guild this member is part of. nick : str The nickname of the member. mute : bool Whether this member is server voice-muted. deaf : bool Whether this member is server voice-deafened. joined_at : datetime When this user joined the guild. roles : list(snowflake) Roles this member is part of. """ user = Field(User) guild_id = Field(snowflake) nick = Field(text) mute = Field(bool) deaf = Field(bool) joined_at = Field(datetime) roles = ListField(snowflake) def __str__(self): return self.user.__str__() @property def name(self): """ The nickname of this user if set, otherwise their username """ return self.nick or self.user.username def get_voice_state(self): """ Returns ------- Optional[:class:`disco.types.voice.VoiceState`] Returns the voice state for the member if they are currently connected to the guild's voice server. """ return self.guild.get_voice_state(self) def kick(self): """ Kicks the member from the guild. """ self.client.api.guilds_members_kick(self.guild.id, self.user.id) def ban(self, delete_message_days=0): """ Bans the member from the guild. Args ---- delete_message_days : int The number of days to retroactively delete messages for. """ self.guild.create_ban(self, delete_message_days) def unban(self): """ Unbans the member from the guild. """ self.guild.delete_ban(self) def set_nickname(self, nickname=None): """ Sets the member's nickname (or clears it if None). Args ---- nickname : Optional[str] The nickname (or none to reset) to set. """ if self.client.state.me.id == self.user.id: self.client.api.guilds_members_me_nick(self.guild.id, nick=nickname or '') else: self.client.api.guilds_members_modify(self.guild.id, self.user.id, nick=nickname or '') def modify(self, **kwargs): self.client.api.guilds_members_modify(self.guild.id, self.user.id, **kwargs) def add_role(self, role): self.client.api.guilds_members_roles_add(self.guild.id, self.user.id, to_snowflake(role)) def remove_role(self, role): self.client.api.guilds_members_roles_remove(self.guild.id, self.user.id, to_snowflake(role)) @cached_property def owner(self): return self.guild.owner_id == self.id @cached_property def mention(self): if self.nick: return '<@!{}>'.format(self.id) return self.user.mention @property def id(self): """ Alias to the guild members user id. """ return self.user.id @cached_property def guild(self): return self.client.state.guilds.get(self.guild_id) @cached_property def permissions(self): return self.guild.get_permissions(self)
class Guild(SlottedModel, Permissible): """ A guild object. Attributes ---------- id : snowflake The id of this guild. owner_id : snowflake The id of the owner. afk_channel_id : snowflake The id of the afk channel. embed_channel_id : snowflake The id of the embed channel. system_channel_id : snowflake The id of the system channel. name : str Guild's name. icon : str Guild's icon hash splash : str Guild's splash image hash region : str Voice region. afk_timeout : int Delay after which users are automatically moved to the afk channel. embed_enabled : bool Whether the guild's embed is enabled. verification_level : int The verification level used by the guild. mfa_level : int The MFA level used by the guild. features : list(str) Extra features enabled for this guild. members : dict(snowflake, :class:`GuildMember`) All of the guild's members. channels : dict(snowflake, :class:`disco.types.channel.Channel`) All of the guild's channels. roles : dict(snowflake, :class:`Role`) All of the guild's roles. emojis : dict(snowflake, :class:`GuildEmoji`) All of the guild's emojis. voice_states : dict(str, :class:`disco.types.voice.VoiceState`) All of the guild's voice states. """ id = Field(snowflake) owner_id = Field(snowflake) afk_channel_id = Field(snowflake) embed_channel_id = Field(snowflake) system_channel_id = Field(snowflake) name = Field(text) icon = Field(text) splash = Field(text) region = Field(text) afk_timeout = Field(int) embed_enabled = Field(bool) verification_level = Field(enum(VerificationLevel)) explicit_content_filter = Field(enum(ExplicitContentFilterLevel)) default_message_notifications = Field( enum(DefaultMessageNotificationsLevel)) mfa_level = Field(int) features = ListField(str) members = AutoDictField(GuildMember, 'id') channels = AutoDictField(Channel, 'id') roles = AutoDictField(Role, 'id') emojis = AutoDictField(GuildEmoji, 'id') voice_states = AutoDictField(VoiceState, 'session_id') member_count = Field(int) def __init__(self, *args, **kwargs): super(Guild, self).__init__(*args, **kwargs) self.attach(six.itervalues(self.channels), {'guild_id': self.id}) self.attach(six.itervalues(self.members), {'guild_id': self.id}) self.attach(six.itervalues(self.roles), {'guild_id': self.id}) self.attach(six.itervalues(self.emojis), {'guild_id': self.id}) self.attach(six.itervalues(self.voice_states), {'guild_id': self.id}) @cached_property def owner(self): return self.members.get(self.owner_id) def get_permissions(self, member): """ Get the permissions a user has in this guild. Returns ------- :class:`disco.types.permissions.PermissionValue` Computed permission value for the user. """ if not isinstance(member, GuildMember): member = self.get_member(member) # Owner has all permissions if self.owner_id == member.id: return PermissionValue(Permissions.ADMINISTRATOR) # Our value starts with the guilds default (@everyone) role permissions value = PermissionValue(self.roles.get(self.id).permissions) # Iterate over all roles the user has (plus the @everyone role) for role in map(self.roles.get, member.roles + [self.id]): value += role.permissions return value def get_voice_state(self, user): """ Attempt to get a voice state for a given user (who should be a member of this guild). Returns ------- :class:`disco.types.voice.VoiceState` The voice state for the user in this guild. """ user = to_snowflake(user) for state in six.itervalues(self.voice_states): if state.user_id == user: return state def get_member(self, user): """ Attempt to get a member from a given user. Returns ------- :class:`GuildMember` The guild member object for the given user. """ user = to_snowflake(user) if user not in self.members: try: self.members[user] = self.client.api.guilds_members_get( self.id, user) except APIException: return return self.members.get(user) def create_role(self, **kwargs): """ Create a new role. Returns ------- :class:`Role` The newly created role. """ return self.client.api.guilds_roles_create(self.id, **kwargs) def delete_role(self, role, **kwargs): """ Delete a role. """ self.client.api.guilds_roles_delete(self.id, to_snowflake(role), **kwargs) def update_role(self, role, **kwargs): if 'permissions' in kwargs and isinstance(kwargs['permissions'], PermissionValue): kwargs['permissions'] = kwargs['permissions'].value return self.client.api.guilds_roles_modify(self.id, to_snowflake(role), **kwargs) def request_guild_members(self, query=None, limit=0): self.client.gw.request_guild_members(self.id, query, limit) def sync(self): warnings.warn( 'Guild.sync has been deprecated in place of Guild.request_guild_members', DeprecationWarning) self.request_guild_members() def get_bans(self): return self.client.api.guilds_bans_list(self.id) def delete_ban(self, user, **kwargs): self.client.api.guilds_bans_delete(self.id, to_snowflake(user), **kwargs) def create_ban(self, user, *args, **kwargs): self.client.api.guilds_bans_create(self.id, to_snowflake(user), *args, **kwargs) def create_channel(self, *args, **kwargs): warnings.warn( 'Guild.create_channel will be deprecated soon, please use:' ' Guild.create_text_channel or Guild.create_category or Guild.create_voice_channel', DeprecationWarning) return self.client.api.guilds_channels_create(self.id, *args, **kwargs) def create_category(self, name, permission_overwrites=[], position=None, reason=None): """ Creates a category within the guild. """ return self.client.api.guilds_channels_create( self.id, ChannelType.GUILD_CATEGORY, name=name, permission_overwrites=permission_overwrites, position=position, reason=reason, ) def create_text_channel(self, name, permission_overwrites=[], parent_id=None, nsfw=None, position=None, reason=None): """ Creates a text channel within the guild. """ return self.client.api.guilds_channels_create( self.id, ChannelType.GUILD_TEXT, name=name, permission_overwrites=permission_overwrites, parent_id=parent_id, nsfw=nsfw, position=position, reason=reason, ) def create_voice_channel(self, name, permission_overwrites=[], parent_id=None, bitrate=None, user_limit=None, position=None, reason=None): """ Creates a voice channel within the guild. """ return self.client.api.guilds_channels_create( self.id, ChannelType.GUILD_VOICE, name=name, permission_overwrites=permission_overwrites, parent_id=parent_id, bitrate=bitrate, user_limit=user_limit, position=position, reason=None) def leave(self): return self.client.api.users_me_guilds_delete(self.id) def get_invites(self): return self.client.api.guilds_invites_list(self.id) def get_emojis(self): return self.client.api.guilds_emojis_list(self.id) def get_icon_url(self, fmt='webp', size=1024): if not self.icon: return '' return 'https://media.discordapp.net/icons/{}/{}.{}?size={}'.format( self.id, self.icon, fmt, size) def get_splash_url(self, fmt='webp', size=1024): if not self.splash: return '' return 'https://media.discordapp.net/splashes/{}/{}.{}?size={}'.format( self.id, self.splash, fmt, size) @property def icon_url(self): return self.get_icon_url() @property def splash_url(self): return self.get_splash_url() @property def system_channel(self): return self.channels.get(self.system_channel_id) @property def audit_log(self): return self.audit_log_iter() def audit_log_iter(self, **kwargs): return Paginator(self.client.api.guilds_auditlogs_list, 'before', self.id, **kwargs) def get_audit_log_entries(self, *args, **kwargs): return self.client.api.guilds_auditlogs_list(self.id, *args, **kwargs)
class Guild(SlottedModel, Permissible): """ A guild object. Attributes ---------- id : snowflake The id of this guild. owner_id : snowflake The id of the owner. afk_channel_id : snowflake The id of the afk channel. embed_channel_id : snowflake The id of the embed channel. name : str Guild's name. icon : str Guild's icon (as PNG binary data). splash : str Guild's splash image (as PNG binary data). region : str Voice region. afk_timeout : int Delay after which users are automatically moved to the afk channel. embed_enabled : bool Whether the guild's embed is enabled. verification_level : int The verification level used by the guild. mfa_level : int The MFA level used by the guild. features : list(str) Extra features enabled for this guild. members : dict(snowflake, :class:`GuildMember`) All of the guild's members. channels : dict(snowflake, :class:`disco.types.channel.Channel`) All of the guild's channels. roles : dict(snowflake, :class:`Role`) All of the guild's roles. emojis : dict(snowflake, :class:`GuildEmoji`) All of the guild's emojis. voice_states : dict(str, :class:`disco.types.voice.VoiceState`) All of the guild's voice states. """ id = Field(snowflake) owner_id = Field(snowflake) afk_channel_id = Field(snowflake) embed_channel_id = Field(snowflake) name = Field(text) icon = Field(binary) splash = Field(binary) region = Field(str) afk_timeout = Field(int) embed_enabled = Field(bool) verification_level = Field(enum(VerificationLevel)) mfa_level = Field(int) features = ListField(str) members = AutoDictField(GuildMember, 'id') channels = AutoDictField(Channel, 'id') roles = AutoDictField(Role, 'id') emojis = AutoDictField(GuildEmoji, 'id') voice_states = AutoDictField(VoiceState, 'session_id') member_count = Field(int) synced = Field(bool, default=False) def __init__(self, *args, **kwargs): super(Guild, self).__init__(*args, **kwargs) self.attach(six.itervalues(self.channels), {'guild_id': self.id}) self.attach(six.itervalues(self.members), {'guild_id': self.id}) self.attach(six.itervalues(self.roles), {'guild_id': self.id}) self.attach(six.itervalues(self.emojis), {'guild_id': self.id}) self.attach(six.itervalues(self.voice_states), {'guild_id': self.id}) @cached_property def owner(self): return self.members.get(self.owner_id) def get_permissions(self, member): """ Get the permissions a user has in this guild. Returns ------- :class:`disco.types.permissions.PermissionValue` Computed permission value for the user. """ if not isinstance(member, GuildMember): member = self.get_member(member) # Owner has all permissions if self.owner_id == member.id: return PermissionValue(Permissions.ADMINISTRATOR) value = PermissionValue(self.roles.get(self.id).permissions) for role in map(self.roles.get, member.roles): value += role.permissions return value def get_voice_state(self, user): """ Attempt to get a voice state for a given user (who should be a member of this guild). Returns ------- :class:`disco.types.voice.VoiceState` The voice state for the user in this guild. """ user = to_snowflake(user) for state in six.itervalues(self.voice_states): if state.user_id == user: return state def get_member(self, user): """ Attempt to get a member from a given user. Returns ------- :class:`GuildMember` The guild member object for the given user. """ user = to_snowflake(user) if user not in self.members: try: self.members[user] = self.client.api.guilds_members_get( self.id, user) except APIException: return return self.members.get(user) def create_role(self): """ Create a new role. Returns ------- :class:`Role` The newly created role. """ return self.client.api.guilds_roles_create(self.id) def delete_role(self, role): """ Delete a role. """ self.client.api.guilds_roles_delete(self.id, to_snowflake(role)) def update_role(self, role): return self.client.api.guilds_roles_modify( self.id, role.id, **{ 'name': role.name, 'permissions': role.permissions.value, 'position': role.position, 'color': role.color, 'hoist': role.hoist, 'mentionable': role.mentionable, }) def sync(self): if self.synced: return self.synced = True self.client.gw.send(OPCode.REQUEST_GUILD_MEMBERS, { 'guild_id': self.id, 'query': '', 'limit': 0, }) def get_bans(self): return self.client.api.guilds_bans_list(self.id) def delete_ban(self, user): self.client.api.guilds_bans_delete(self.id, to_snowflake(user)) def create_ban(self, user, delete_message_days=0): self.client.api.guilds_bans_create(self.id, to_snowflake(user), delete_message_days) def create_channel(self, *args, **kwargs): return self.client.api.guilds_channels_create(self.id, *args, **kwargs) def leave(self): return self.client.api.users_me_guilds_delete(self.id)
class Channel(SlottedModel, Permissible): """ Represents a Discord Channel. Attributes ---------- id : snowflake The channel ID. guild_id : Optional[snowflake] The guild id this channel is part of. name : str The channel's name. topic : str The channel's topic. position : int The channel's position. bitrate : int The channel's bitrate. recipients: list(:class:`disco.types.user.User`) Members of this channel (if this is a DM channel). type : :const:`ChannelType` The type of this channel. overwrites : dict(snowflake, :class:`disco.types.channel.PermissionOverwrite`) Channel permissions overwrites. """ id = Field(snowflake) guild_id = Field(snowflake) name = Field(text) topic = Field(text) last_message_id = Field(snowflake) position = Field(int) bitrate = Field(int) recipients = ListField(User) type = Field(enum(ChannelType)) overwrites = AutoDictField(PermissionOverwrite, 'id', alias='permission_overwrites') def __init__(self, *args, **kwargs): super(Channel, self).__init__(*args, **kwargs) self.attach(six.itervalues(self.overwrites), { 'channel_id': self.id, 'channel': self }) def __str__(self): return u'#{}'.format(self.name) def __repr__(self): return u'<Channel {} ({})>'.format(self.id, self) def get_permissions(self, user): """ Get the permissions a user has in the channel. Returns ------- :class:`disco.types.permissions.PermissionValue` Computed permission value for the user. """ if not self.guild_id: return Permissions.ADMINISTRATOR member = self.guild.members.get(user.id) base = self.guild.get_permissions(user) for ow in six.itervalues(self.overwrites): if ow.id != user.id and ow.id not in member.roles: continue base -= ow.deny base += ow.allow return base @property def mention(self): return '<#{}>'.format(self.id) @property def is_guild(self): """ Whether this channel belongs to a guild. """ return self.type in (ChannelType.GUILD_TEXT, ChannelType.GUILD_VOICE) @property def is_dm(self): """ Whether this channel is a DM (does not belong to a guild). """ return self.type in (ChannelType.DM, ChannelType.GROUP_DM) @property def is_voice(self): """ Whether this channel supports voice. """ return self.type in (ChannelType.GUILD_VOICE, ChannelType.GROUP_DM) @property def messages(self): """ a default :class:`MessageIterator` for the channel. """ return self.messages_iter() @cached_property def guild(self): """ Guild this channel belongs to (if relevant). """ return self.client.state.guilds.get(self.guild_id) def messages_iter(self, **kwargs): """ Creates a new :class:`MessageIterator` for the channel with the given keyword arguments. """ return MessageIterator(self.client, self, **kwargs) def get_message(self, message): return self.client.api.channels_messages_get(self.id, to_snowflake(message)) def get_invites(self): """ Returns ------- list(:class:`disco.types.invite.Invite`) All invites for this channel. """ return self.client.api.channels_invites_list(self.id) def create_invite(self, *args, **kwargs): from disco.types.invite import Invite return Invite.create(self, *args, **kwargs) def get_pins(self): """ Returns ------- list(:class:`disco.types.message.Message`) All pinned messages for this channel. """ return self.client.api.channels_pins_list(self.id) def create_pin(self, message): self.client.api.channels_pins_create(self.id, to_snowflake(message)) def delete_pin(self, message): self.client.api.channels_pins_delete(self.id, to_snowflake(message)) def get_webhooks(self): return self.client.api.channels_webhooks_list(self.id) def create_webhook(self, name=None, avatar=None): return self.client.api.channels_webhooks_create(self.id, name, avatar) def send_message(self, content, nonce=None, tts=False, attachment=None, embed=None): """ Send a message in this channel. Parameters ---------- content : str The message contents to send. nonce : Optional[snowflake] The nonce to attach to the message. tts : Optional[bool] Whether this is a TTS message. Returns ------- :class:`disco.types.message.Message` The created message. """ return self.client.api.channels_messages_create( self.id, content, nonce, tts, attachment, embed) def connect(self, *args, **kwargs): """ Connect to this channel over voice. """ assert self.is_voice, 'Channel must support voice to connect' vc = VoiceClient(self) vc.connect(*args, **kwargs) return vc def create_overwrite(self, *args, **kwargs): return PermissionOverwrite.create(self, *args, **kwargs) def delete_message(self, message): """ Deletes a single message from this channel. Args ---- message : snowflake|:class:`disco.types.message.Message` The message to delete. """ self.client.api.channels_messages_delete(self.id, to_snowflake(message)) @one_or_many def delete_messages(self, messages): """ Deletes a set of messages using the correct API route based on the number of messages passed. Args ---- messages : list[snowflake|:class:`disco.types.message.Message`] List of messages (or message ids) to delete. All messages must originate from this channel. """ messages = map(to_snowflake, messages) if not messages: return if self.can(self.client.state.me, Permissions.MANAGE_MESSAGES) and len(messages) > 2: for chunk in chunks(messages, 100): self.client.api.channels_messages_delete_bulk(self.id, chunk) else: for msg in messages: self.delete_message(msg) def delete(self): assert (self.is_dm or self.guild.can( self.client.state.me, Permissions.MANAGE_GUILD)), 'Invalid Permissions' self.client.api.channels_delete(self.id) def close(self): """ Closes a DM channel. This is intended as a safer version of `delete`, enforcing that the channel is actually a DM. """ assert self.is_dm, 'Cannot close non-DM channel' self.delete()