Ejemplo n.º 1
0
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(str)
    timestamp = Field(lazy_datetime)
    color = Field(int)
    footer = Field(MessageEmbedFooter)
    image = Field(MessageEmbedImage)
    thumbnail = Field(MessageEmbedThumbnail)
    video = Field(MessageEmbedVideo)
    author = Field(MessageEmbedAuthor)
    fields = Field(listof(MessageEmbedField))
Ejemplo n.º 2
0
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 = Field(listof(snowflake))

    @cached_property
    def guild(self):
        return self.client.state.guilds.get(self.guild_id)
Ejemplo n.º 3
0
Archivo: events.py Proyecto: jhgg/disco
class Ready(GatewayEvent):
    """
    Sent after the initial gateway handshake is complete. Contains data required
    for bootstrapping the client's states.
    """
    version = Field(int, alias='v')
    session_id = Field(str)
    user = Field(User)
    guilds = Field(listof(Guild))
Ejemplo n.º 4
0
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 = Field(listof(snowflake))
Ejemplo n.º 5
0
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 = Field(listof(Emoji))
Ejemplo n.º 6
0
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 = Field(listof(Guild))
    private_channels = Field(listof(Channel))
Ejemplo n.º 7
0
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 = Field(listof(snowflake))
Ejemplo n.º 8
0
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 = Field(listof(GuildMember))

    @property
    def guild(self):
        return self.client.state.guilds.get(self.guild_id)
Ejemplo n.º 9
0
class Emoji(Model):
    """
    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)
    name = Field(text)
    require_colons = Field(bool)
    managed = Field(bool)
    roles = Field(listof(snowflake))
Ejemplo n.º 10
0
class Channel(Model, 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 channels name.
    topic : str
        The channels topic.
    position : int
        The channels position.
    bitrate : int
        The channels 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 = Field(listof(User))
    type = Field(enum(ChannelType))
    overwrites = Field(dictof(PermissionOverwrite, key='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 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 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()

    def messages_iter(self, **kwargs):
        """
        Creates a new :class:`MessageIterator` for the channel with the given
        keyword arguments
        """
        return MessageIterator(self.client, self.id, **kwargs)

    @cached_property
    def guild(self):
        """
        Guild this channel belongs to (if relevant)
        """
        return self.client.state.guilds.get(self.guild_id)

    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 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 send_message(self, content, nonce=None, tts=False):
        """
        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)

    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, entity, allow=0, deny=0):
        from disco.types.guild import Role

        type = PermissionOverwriteType.ROLE if isinstance(
            entity, Role) else PermissionOverwriteType.MEMBER
        ow = PermissionOverwrite(id=entity.id,
                                 type=type,
                                 allow=allow,
                                 deny=deny)

        ow.channel_id = self.id
        ow.channel = self

        return self.update_overwrite(ow)

    def update_overwrite(self, ow):
        self.client.api.channels_permissions_modify(
            self.id, ow.id, ow.allow.value if ow.allow else 0,
            ow.deny.value if ow.deny else 0, ow.type.name)
        return ow

    def delete_overwrite(self, ow):
        self.client.api.channels_permissions_delete(self.id, ow.id)

    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 len(messages) <= 2:
            for msg in messages:
                self.delete_message(msg)
        else:
            for chunk in chunks(messages, 100):
                self.client.api.channels_messages_delete_bulk(self.id, chunk)
Ejemplo n.º 11
0
class Message(Model):
    """
    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 : Optional[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, :class:`disco.types.user.User`)
        All users mentioned within this message.
    mention_roles : list(snowflake)
        All roles mentioned within this message.
    embeds : list(:class:`MessageEmbed`)
        All embeds for this message.
    attachments : list(:class:`MessageAttachment`)
        All attachments for this message.
    """
    id = Field(snowflake)
    channel_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 = Field(dictof(User, key='id'))
    mention_roles = Field(listof(snowflake))
    embeds = Field(listof(MessageEmbed))
    attachments = Field(dictof(MessageAttachment, key='id'))

    def __str__(self):
        return '<Message {} ({})>'.format(self.id, self.channel_id)

    @cached_property
    def guild(self):
        """
        Returns
        -------
        :class:`disco.types.guild.Guild`
            The guild (if applicable) this message was created in.
        """
        return self.channel.guild

    @cached_property
    def member(self):
        """
        Returns
        -------
        :class:`disco.types.guild.GuildMember`
            The guild member (if applicable) that sent this message.
        """
        return self.channel.guild.get_member(self.author)

    @cached_property
    def channel(self):
        """
        Returns
        -------
        :class:`disco.types.channel.Channel`
            The channel this message was created in.
        """
        return self.client.state.channels.get(self.channel_id)

    def reply(self, *args, **kwargs):
        """
        Reply to this message (proxys arguments to
        :func:`disco.types.channel.Channel.send_message`)

        Returns
        -------
        :class:`Message`
            The created message object.
        """
        return self.channel.send_message(*args, **kwargs)

    def edit(self, content):
        """
        Edit this message

        Args
        ----
        content : str
            The new edited contents of the message.

        Returns
        -------
        :class:`Message`
            The edited message object.
        """
        return self.client.api.channels_messages_modify(self.channel_id, self.id, content)

    def delete(self):
        """
        Delete this message.

        Returns
        -------
        :class:`Message`
            The deleted message object.
        """
        return self.client.api.channels_messages_delete(self.channel_id, self.id)

    def is_mentioned(self, entity):
        """
        Returns
        -------
        bool
            Whether the give entity was mentioned.
        """
        id = to_snowflake(entity)
        return id in self.mentions or id in self.mention_roles

    @cached_property
    def without_mentions(self):
        """
        Returns
        -------
        str
            the message contents with all valid mentions removed.
        """
        return self.replace_mentions(
            lambda u: '',
            lambda r: '')

    def replace_mentions(self, user_replace, role_replace):
        """
        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.
        """
        if not self.mentions and not self.mention_roles:
            return

        def replace(match):
            id = match.group(0)
            if id in self.mention_roles:
                return role_replace(id)
            else:
                return user_replace(self.mentions.get(id))

        return re.sub('<@!?([0-9]+)>', replace, self.content)
Ejemplo n.º 12
0
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 = Field(listof(str))
    members = Field(dictof(GuildMember, key='id'))
    channels = Field(dictof(Channel, key='id'))
    roles = Field(dictof(Role, key='id'))
    emojis = Field(dictof(GuildEmoji, key='id'))
    voice_states = Field(dictof(VoiceState, key='session_id'))
    member_count = Field(int)
    presences = Field(listof(Presence))

    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})

    def get_permissions(self, user):
        """
        Get the permissions a user has in this guild.

        Returns
        -------
        :class:`disco.types.permissions.PermissionValue`
            Computed permission value for the user.
        """
        if self.owner_id == user.id:
            return PermissionValue(Permissions.ADMINISTRATOR)

        member = self.get_member(user)
        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)
Ejemplo n.º 13
0
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(str)
    roles = Field(listof(snowflake))

    def __str__(self):
        return self.user.__str__()

    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 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.
        """
        self.client.api.guilds_members_modify(self.guild.id, self.user.id, nick=nickname or '')

    def add_role(self, role):
        roles = self.roles + [role.id]
        self.client.api.guilds_members_modify(self.guild.id, self.user.id, roles=roles)

    @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)
Ejemplo n.º 14
0
Archivo: events.py Proyecto: jhgg/disco
class PresenceUpdate(GatewayEvent):
    """
    Sent when a user's presence is updated.
    """
    guild_id = Field(snowflake)
    roles = Field(listof(snowflake))
Ejemplo n.º 15
0
Archivo: events.py Proyecto: jhgg/disco
class MessageDeleteBulk(GatewayEvent):
    """
    Sent when multiple messages are deleted from a channel.
    """
    channel_id = Field(snowflake)
    ids = Field(listof(snowflake))
Ejemplo n.º 16
0
Archivo: events.py Proyecto: jhgg/disco
class GuildMembersChunk(GatewayEvent):
    """
    Sent in response to a member's chunk request.
    """
    guild_id = Field(snowflake)
    members = Field(listof(GuildMember))