Exemple #1
0
from disco.api.http import APIException
from disco.types.permissions import Permissions

from rowboat.redis import rdb
from rowboat.util.stats import timed
from rowboat.util.zalgo import ZALGO_RE
from rowboat.plugins import RowboatPlugin as Plugin
from rowboat.types import SlottedModel, Field, ListField, DictField, ChannelField, snowflake, lower
from rowboat.types.plugin import PluginConfig
from rowboat.models.message import Message
from rowboat.plugins.modlog import Actions
from rowboat.constants import INVITE_LINK_RE, URL_RE

CensorReason = Enum(
    'INVITE',
    'DOMAIN',
    'WORD',
    'ZALGO',
)


class CensorSubConfig(SlottedModel):
    filter_zalgo = Field(bool, default=True)

    filter_invites = Field(bool, default=True)
    invites_guild_whitelist = ListField(snowflake, default=[])
    invites_whitelist = ListField(lower, default=[])
    invites_blacklist = ListField(lower, default=[])

    filter_domains = Field(bool, default=True)
    domains_whitelist = ListField(lower, default=[])
    domains_blacklist = ListField(lower, default=[])
Exemple #2
0
from disco.util.snowflake import to_snowflake
from disco.util.functional import cached_property
from disco.types.base import (
    SlottedModel, Field, ListField, AutoDictField, DictField, snowflake, text, enum, datetime
)
from disco.types.user import User
from disco.types.voice import VoiceState
from disco.types.channel import Channel
from disco.types.message import Emoji
from disco.types.permissions import PermissionValue, Permissions, Permissible


VerificationLevel = Enum(
    NONE=0,
    LOW=1,
    MEDIUM=2,
    HIGH=3,
    EXTREME=4,
)

ExplicitContentFilterLevel = Enum(
    NONE=0,
    WITHOUT_ROLES=1,
    ALL=2
)

DefaultMessageNotificationsLevel = Enum(
    ALL_MESSAGES=0,
    ONLY_MENTIONS=1,
)
Exemple #3
0
from holster.enum import Enum

from disco.types.base import SlottedModel, Field, snowflake, text, with_equality, with_hash

DefaultAvatars = Enum(
    BLURPLE=0,
    GREY=1,
    GREEN=2,
    ORANGE=3,
    RED=4,
)


class User(SlottedModel, with_equality('id'), with_hash('id')):
    id = Field(snowflake)
    username = Field(text)
    avatar = Field(text)
    discriminator = Field(text)
    bot = Field(bool, default=False)
    verified = Field(bool)
    email = Field(text)

    presence = Field(None)

    def get_avatar_url(self, fmt='webp', size=1024):
        if not self.avatar:
            return 'https://cdn.discordapp.com/embed/avatars/{}.png'.format(
                self.default_avatar.value)

        return 'https://cdn.discordapp.com/avatars/{}/{}.{}?size={}'.format(
            self.id, self.avatar, fmt, size)
Exemple #4
0
from disco.bot import CommandLevels
from disco.types.base import UNSET, cached_property
from disco.util.snowflake import to_unix, to_datetime
from disco.util.sanitize import S

from rowboat.plugins import RowboatPlugin as Plugin
from rowboat.types import SlottedModel, Field, ListField, DictField, ChannelField, snowflake
from rowboat.types.plugin import PluginConfig
from rowboat.models.message import Message, MessageArchive
from rowboat.models.guild import Guild
from rowboat.util import ordered_load, MetaException

from .pump import ModLogPump

# Dynamically updated by the plugin
Actions = Enum()

URL_REGEX = re.compile(r'(https?://[^\s]+)')


def filter_urls(content):
    return URL_REGEX.sub(r'<\1>', content)


class ChannelConfig(SlottedModel):
    compact = Field(bool, default=True)
    include = ListField(Actions)
    exclude = ListField(Actions)
    rich = ListField(Actions)

    timestamps = Field(bool, default=False)
Exemple #5
0
class MessageIterator(object):
    """
    An iterator which supports scanning through the messages for a channel.

    Parameters
    ----------
    client : :class:`disco.client.Client`
        The disco client instance to use when making requests.
    channel : `Channel`
        The channel to iterate within.
    direction : :attr:`MessageIterator.Direction`
        The direction in which this iterator will move.
    bulk : bool
        If true, this iterator will yield messages in list batches, otherwise each
        message will be yield individually.
    before : snowflake
        The message to begin scanning at.
    after : snowflake
        The message to begin scanning at.
    chunk_size : int
        The number of messages to request per API call.
    """
    Direction = Enum('UP', 'DOWN')

    def __init__(self,
                 client,
                 channel,
                 direction=Direction.UP,
                 bulk=False,
                 before=None,
                 after=None,
                 chunk_size=100):
        self.client = client
        self.channel = channel
        self.direction = direction
        self.bulk = bulk
        self.before = before
        self.after = after
        self.chunk_size = chunk_size

        self.last = None
        self._buffer = []

        if not any((before, after)) and self.direction == self.Direction.DOWN:
            raise Exception(
                'Must specify either before or after for downward seeking')

    def fill(self):
        """
        Fills the internal buffer up with :class:`disco.types.message.Message` objects from the API.
        """
        self._buffer = self.client.api.channels_messages_list(
            self.channel.id,
            before=self.before,
            after=self.after,
            limit=self.chunk_size)

        if not len(self._buffer):
            raise StopIteration

        self.after = None
        self.before = None

        if self.direction == self.Direction.UP:
            self.before = self._buffer[-1].id

        else:
            self._buffer.reverse()
            self.after = self._buffer[-1].id

    def next(self):
        return self.__next__()

    def __iter__(self):
        return self

    def __next__(self):
        if not len(self._buffer):
            self.fill()

        if self.bulk:
            res = self._buffer
            self._buffer = []
            return res
        else:
            return self._buffer.pop()
Exemple #6
0
from holster.enum import Enum

from disco.types.base import SlottedModel, Field, datetime, enum
from disco.types.user import User
from disco.types.guild import Guild
from disco.types.channel import Channel

InviteTargetUserType = Enum(STREAM=1)


class Invite(SlottedModel):
    """
    An invite object.

    Attributes
    ----------
    code : str
        The invite code.
    guild : :class:`disco.types.guild.Guild`
        The guild this invite is for.
    channel : :class:`disco.types.channel.Channel`
        The channel this invite is for.
    target_user : :class:`disco.types.user.User`
        The user this invite targets.
    target_user_type : int
        The type of user target for this invite.
    approximate_presence_count : int
        The approximate count of online members.
    approximate_member_count : int
        The approximate count of total members.
    inviter : :class:`disco.types.user.User`
Exemple #7
0
from holster.enum import Enum
from holster.emitter import Priority
from disco.util.sanitize import ZERO_WIDTH_SPACE

from rowboat.plugins import RowboatPlugin as Plugin
from rowboat.redis import rdb
from rowboat.plugins.modlog import Actions
from rowboat.plugins.censor import URL_RE
from rowboat.util.leakybucket import LeakyBucket
from rowboat.util.stats import timed
from rowboat.types.plugin import PluginConfig
from rowboat.types import SlottedModel, DictField, Field
from rowboat.models.user import Infraction
from rowboat.models.message import Message, EMOJI_RE

PunishmentType = Enum('NONE', 'MUTE', 'KICK', 'TEMPBAN', 'BAN', 'TEMPMUTE')


class CheckConfig(SlottedModel):
    count = Field(int)
    interval = Field(int)
    meta = Field(dict, default=None)


class SubConfig(SlottedModel):
    max_messages = Field(CheckConfig, default=None)
    max_mentions = Field(CheckConfig, default=None)
    max_links = Field(CheckConfig, default=None)
    max_emojis = Field(CheckConfig, default=None)
    max_newlines = Field(CheckConfig, default=None)
    max_attachments = Field(CheckConfig, default=None)
Exemple #8
0
from holster.enum import Enum

SEND = 1
RECV = 2

OPCode = Enum(
    DISPATCH=0,
    HEARTBEAT=1,
    IDENTIFY=2,
    STATUS_UPDATE=3,
    VOICE_STATE_UPDATE=4,
    VOICE_SERVER_PING=5,
    RESUME=6,
    RECONNECT=7,
    REQUEST_GUILD_MEMBERS=8,
    INVALID_SESSION=9,
    HELLO=10,
    HEARTBEAT_ACK=11,
    GUILD_SYNC=12,
)
Exemple #9
0
    @property
    def mention(self):
        return '<@{}>'.format(self.id)

    def to_string(self):
        return '{}#{}'.format(self.username, self.discriminator)

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

    def on_create(self):
        self.client.state.users[self.id] = self


GameType = Enum(
    DEFAULT=0,
    STREAMING=1,
)

Status = Enum('ONLINE', 'IDLE', 'DND', 'INVISIBLE', 'OFFLINE')


class Game(Model):
    type = Field(GameType)
    name = Field(text)
    url = Field(text)


class Presence(Model):
    user = Field(User)
    game = Field(Game)
    status = Field(Status)
Exemple #10
0
import gevent

from collections import namedtuple

try:
    import nacl.secret
except ImportError:
    print('WARNING: nacl is not installed, voice support is disabled')

from holster.enum import Enum

from disco.util.logging import LoggingClass

AudioCodecs = ('opus', )

RTPPayloadTypes = Enum(OPUS=0x78)

RTCPPayloadTypes = Enum(
    SENDER_REPORT=200,
    RECEIVER_REPORT=201,
    SOURCE_DESCRIPTION=202,
    BYE=203,
    APP=204,
    RTPFB=205,
    PSFB=206,
)

MAX_UINT32 = 4294967295
MAX_SEQUENCE = 65535

RTP_HEADER_VERSION = 0x80  # Only RTP Version is set here (value of 2 << 6)
Exemple #11
0
import requests

from collections import defaultdict

from holster.enum import Enum
from disco.types.message import MessageEmbed

from rowboat.plugins import RowboatPlugin as Plugin
from rowboat.redis import rdb
from rowboat.models.guild import Guild
from rowboat.types.plugin import PluginConfig
from rowboat.types import SlottedModel, DictField, Field, ChannelField


FormatMode = Enum(
    'PLAIN',
    'PRETTY'
)


class SubRedditConfig(SlottedModel):
    channel = Field(ChannelField)
    mode = Field(FormatMode, default=FormatMode.PRETTY)
    nsfw = Field(bool, default=False)
    text_length = Field(int, default=256)
    include_stats = Field(bool, default=False)


class RedditConfig(PluginConfig):
    # TODO: validate they have less than 3 reddits selected
    subs = DictField(str, SubRedditConfig)
Exemple #12
0
from holster.enum import Enum

from disco.api.http import APIException
from disco.util.snowflake import to_snowflake
from disco.util.functional import cached_property
from disco.types.base import Model, Field, snowflake, listof, dictof, datetime, text, binary, enum
from disco.types.user import User
from disco.types.voice import VoiceState
from disco.types.channel import Channel
from disco.types.permissions import PermissionValue, Permissions, Permissible


VerificationLevel = Enum(
    NONE=0,
    LOW=1,
    MEDIUM=2,
    HIGH=3,
    EXTREME=4,
)


class Emoji(Model):
    """
    An emoji object

    Attributes
    ----------
    id : snowflake
        The ID of this emoji.
    name : str
        The name of this emoji.
Exemple #13
0
class Infraction(BaseModel):
    Types = Enum(
        'MUTE',
        'KICK',
        'TEMPBAN',
        'SOFTBAN',
        'BAN',
        'TEMPMUTE',
        'UNBAN',
        bitmask=False,
    )

    guild_id = BigIntegerField()
    user_id = BigIntegerField()
    actor_id = BigIntegerField(null=True)

    type_ = IntegerField(db_column='type')
    reason = TextField(null=True)
    metadata = BinaryJSONField(default={})

    expires_at = DateTimeField(null=True)
    created_at = DateTimeField(default=datetime.utcnow)
    active = BooleanField(default=True)

    class Meta:
        db_table = 'infractions'

        indexes = ((('guild_id', 'user_id'), False), )

    @staticmethod
    def admin_config(event):
        return getattr(event.base_config.plugins, 'admin', None)

    @classmethod
    def kick(cls, plugin, event, member, reason):
        User.from_disco_user(member.user)
        plugin.bot.plugins.get('ModLogPlugin').create_debounce(
            event,
            member.user.id,
            'kick',
            actor=unicode(event.author)
            if event.author.id != member.id else 'Automatic',
            reason=reason or 'no reason')
        member.kick()
        cls.create(guild_id=member.guild_id,
                   user_id=member.user.id,
                   actor_id=event.author.id,
                   type_=cls.Types.KICK,
                   reason=reason)

    @classmethod
    def tempban(cls, plugin, event, member, reason, expires_at):
        User.from_disco_user(member.user)

        plugin.bot.plugins.get('ModLogPlugin').create_debounce(
            event,
            member.user.id,
            'ban_reason',
            actor=unicode(event.author)
            if event.author.id != member.id else 'Automatic',
            temp=True,
            expires=expires_at,
            reason=reason or 'no reason')

        member.ban()

        cls.create(guild_id=member.guild_id,
                   user_id=member.user.id,
                   actor_id=event.author.id,
                   type_=cls.Types.TEMPBAN,
                   reason=reason,
                   expires_at=expires_at)

    @classmethod
    def softban(cls, plugin, event, member, reason):
        User.from_disco_user(member.user)
        plugin.bot.plugins.get('ModLogPlugin').create_debounce(
            event,
            member.user.id,
            'ban_reason',
            actor=unicode(event.author)
            if event.author.id != member.id else 'Automatic',
            temp=True,
            expires=None,
            reason=reason or 'no reason')

        member.ban(delete_message_days=7)
        member.unban()
        cls.create(guild_id=member.guild_id,
                   user_id=member.user.id,
                   actor_id=event.author.id,
                   type_=cls.Types.SOFTBAN,
                   reason=reason)

    @classmethod
    def ban(cls, plugin, event, member, reason, guild):
        if isinstance(member, (int, long)):
            user_id = member
        else:
            User.from_disco_user(member.user)
            user_id = member.user.id

        plugin.bot.plugins.get('ModLogPlugin').create_debounce(
            event,
            user_id,
            'ban_reason',
            actor=unicode(event.author)
            if event.author.id != user_id else 'Automatic',
            temp=False,
            expires=None,
            reason=reason or 'no reason')

        guild.create_ban(user_id)

        cls.create(guild_id=guild.id,
                   user_id=user_id,
                   actor_id=event.author.id,
                   type_=cls.Types.BAN,
                   reason=reason)

    @classmethod
    def mute(cls, plugin, event, member, reason):
        admin_config = cls.admin_config(event)

        plugin.bot.plugins.get('ModLogPlugin').create_debounce(
            event,
            member.user.id,
            'muted',
            reason=reason,
            expires_at=None,
            actor=unicode(event.author)
            if event.author.id != member.id else 'Automatic',
            role=admin_config.mute_role)

        member.add_role(admin_config.mute_role)
        cls.create(guild_id=event.guild.id,
                   user_id=member.user.id,
                   actor_id=event.author.id,
                   type_=cls.Types.MUTE,
                   reason=reason,
                   metadata={'role': admin_config.mute_role})

    @classmethod
    def tempmute(cls, plugin, event, member, reason, expires_at):
        admin_config = cls.admin_config(event)

        plugin.bot.plugins.get('ModLogPlugin').create_debounce(
            event,
            member.user.id,
            'muted',
            reason=reason,
            expires_at=expires_at,
            actor=unicode(event.author)
            if event.author.id != member.id else 'Automatic',
            role=(admin_config.temp_mute_role or admin_config.mute_role))

        role = (admin_config.temp_mute_role or admin_config.mute_role)
        member.add_role(role)

        cls.create(guild_id=event.guild.id,
                   user_id=member.user.id,
                   actor_id=event.author.id,
                   type_=cls.Types.TEMPMUTE,
                   reason=reason,
                   expires_at=expires_at,
                   metadata={'role': role})
Exemple #14
0
from holster.enum import Enum

VoiceOPCode = Enum(
    IDENTIFY=0,
    SELECT_PROTOCOL=1,
    READY=2,
    HEARTBEAT=3,
    SESSION_DESCRIPTION=4,
    SPEAKING=5,
    HEARTBEAT_ACK=6,
    RESUME=7,
    HELLO=8,
    RESUMED=9,
    CLIENT_DISCONNECT=13,
)
Exemple #15
0
import functools
import unicodedata

from holster.enum import Enum

from disco.types.base import (SlottedModel, Field, ListField, AutoDictField,
                              snowflake, text, datetime, enum)
from disco.util.paginator import Paginator
from disco.util.snowflake import to_snowflake
from disco.util.functional import cached_property
from disco.types.user import User

MessageType = Enum(DEFAULT=0,
                   RECIPIENT_ADD=1,
                   RECIPIENT_REMOVE=2,
                   CALL=3,
                   CHANNEL_NAME_CHANGE=4,
                   CHANNEL_ICON_CHANGE=5,
                   PINS_ADD=6)


class Emoji(SlottedModel):
    id = Field(snowflake)
    name = Field(text)

    def __eq__(self, other):
        if isinstance(other, Emoji):
            return self.id == other.id and self.name == other.name
        raise NotImplementedError

    def to_string(self):
Exemple #16
0
from holster.enum import Enum

VoiceOPCode = Enum(
    IDENTIFY=0,
    SELECT_PROTOCOL=1,
    READY=2,
    HEARTBEAT=3,
    SESSION_DESCRIPTION=4,
    SPEAKING=5,
)
Exemple #17
0
    print('WARNING: nacl is not installed, voice support is disabled')

from holster.enum import Enum
from holster.emitter import Emitter

from disco.gateway.encoding.json import JSONEncoder
from disco.util.websocket import Websocket
from disco.util.logging import LoggingClass
from disco.voice.packets import VoiceOPCode
from disco.gateway.packets import OPCode

VoiceState = Enum(
    DISCONNECTED=0,
    AWAITING_ENDPOINT=1,
    AUTHENTICATING=2,
    CONNECTING=3,
    CONNECTED=4,
    VOICE_CONNECTING=5,
    VOICE_CONNECTED=6,
)


class VoiceException(Exception):
    def __init__(self, msg, client):
        self.voice_client = client
        super(VoiceException, self).__init__(msg)


class UDPVoiceClient(LoggingClass):
    def __init__(self, vc):
        super(UDPVoiceClient, self).__init__()
Exemple #18
0
class Infraction(BaseModel):
    Types = Enum(
        'MUTE',
        'KICK',
        'TEMPBAN',
        'SOFTBAN',
        'BAN',
        'TEMPMUTE',
        'UNBAN',
        'TEMPROLE',
        'WARNING',
        bitmask=False,
    )

    guild_id = BigIntegerField()
    user_id = BigIntegerField()
    actor_id = BigIntegerField(null=True)

    type_ = IntegerField(column_name='type')
    reason = TextField(null=True)
    metadata = BinaryJSONField(default={})

    expires_at = DateTimeField(null=True)
    created_at = DateTimeField(default=datetime.utcnow)
    active = BooleanField(default=True)

    class Meta:
        table_name = 'infractions'

        indexes = ((('guild_id', 'user_id'), False), )

    def serialize(self,
                  guild=None,
                  user=None,
                  actor=None,
                  include_metadata=False):
        base = {
            'id': str(self.id),
            'guild': (guild and guild.serialize()) or {
                'id': str(self.guild_id)
            },
            'user': (user and user.serialize()) or {
                'id': str(self.user_id)
            },
            'actor': (actor and actor.serialize()) or {
                'id': str(self.actor_id)
            },
            'reason': self.reason,
            'expires_at': self.expires_at,
            'created_at': self.created_at,
            'active': self.active,
            'type': {
                'id':
                self.type_,
                'name':
                next(i.name for i in Infraction.Types.attrs
                     if i.index == self.type_)
            }
        }

        if include_metadata:
            base['metadata'] = self.metadata

        return base

    @staticmethod
    def admin_config(event):
        return getattr(event.base_config.plugins, 'admin', None)

    @classmethod
    def temprole(cls, plugin, event, member, role_id, reason, expires_at):
        User.from_disco_user(member.user)

        # TODO: modlog

        member.add_role(role_id, reason=reason)

        cls.create(guild_id=event.guild.id,
                   user_id=member.user.id,
                   actor_id=event.author.id,
                   type_=cls.Types.TEMPROLE,
                   reason=reason,
                   expires_at=expires_at,
                   metadata={'role': role_id})

    @classmethod
    def kick(cls, plugin, event, member, reason):
        from rowboat.plugins.modlog import Actions

        User.from_disco_user(member.user)

        # Prevent the GuildMemberRemove log event from triggering
        plugin.call('ModLogPlugin.create_debounce',
                    event, ['GuildMemberRemove'],
                    user_id=member.user.id)

        member.kick(reason=reason)

        # Create a kick modlog event
        plugin.call('ModLogPlugin.log_action_ext',
                    Actions.MEMBER_KICK,
                    event.guild.id,
                    member=member,
                    actor=event.author
                    if event.author.id != member.id else 'Automatic',
                    reason=reason or 'no reason')

        cls.create(guild_id=member.guild_id,
                   user_id=member.user.id,
                   actor_id=event.author.id,
                   type_=cls.Types.KICK,
                   reason=reason)

    @classmethod
    def tempban(cls, plugin, event, member, reason, expires_at):
        from rowboat.plugins.modlog import Actions
        User.from_disco_user(member.user)

        plugin.call('ModLogPlugin.create_debounce',
                    event, ['GuildMemberRemove', 'GuildBanAdd'],
                    user_id=member.user.id)

        member.ban(reason=reason)

        plugin.call(
            'ModLogPlugin.log_action_ext',
            Actions.MEMBER_TEMPBAN,
            event.guild.id,
            member=member,
            actor=event.author
            if event.author.id != member.id else 'Automatic',
            reason=reason or 'no reason',
            expires=expires_at,
        )

        cls.create(guild_id=member.guild_id,
                   user_id=member.user.id,
                   actor_id=event.author.id,
                   type_=cls.Types.TEMPBAN,
                   reason=reason,
                   expires_at=expires_at)

    @classmethod
    def softban(cls, plugin, event, member, reason):
        from rowboat.plugins.modlog import Actions
        User.from_disco_user(member.user)

        plugin.call('ModLogPlugin.create_debounce',
                    event,
                    ['GuildMemberRemove', 'GuildBanAdd', 'GuildBanRemove'],
                    user_id=member.user.id)

        member.ban(delete_message_days=7, reason=reason)
        member.unban(reason=reason)

        plugin.call('ModLogPlugin.log_action_ext',
                    Actions.MEMBER_SOFTBAN,
                    event.guild.id,
                    member=member,
                    actor=event.author
                    if event.author.id != member.id else 'Automatic',
                    reason=reason or 'no reason')

        cls.create(guild_id=member.guild_id,
                   user_id=member.user.id,
                   actor_id=event.author.id,
                   type_=cls.Types.SOFTBAN,
                   reason=reason)

    @classmethod
    def ban(cls, plugin, event, member, reason, guild, delete_message_days=0):
        from rowboat.plugins.modlog import Actions
        if isinstance(member, int):
            user_id = member
        else:
            User.from_disco_user(member.user)
            user_id = member.user.id

        plugin.call(
            'ModLogPlugin.create_debounce',
            event,
            ['GuildMemberRemove', 'GuildBanAdd'],
            user_id=user_id,
        )

        guild.create_ban(
            user_id,
            delete_message_days if delete_message_days <= 7 else 7,
            reason=reason)

        plugin.call(
            'ModLogPlugin.log_action_ext',
            Actions.MEMBER_BAN,
            guild.id,
            user=member,
            user_id=user_id,
            actor=event.author if event.author.id != user_id else 'Automatic',
            reason=reason or 'no reason')

        cls.create(guild_id=guild.id,
                   user_id=user_id,
                   actor_id=event.author.id,
                   type_=cls.Types.BAN,
                   reason=reason)

    @classmethod
    def warn(cls, plugin, event, member, reason, guild):
        from rowboat.plugins.modlog import Actions
        User.from_disco_user(member.user)
        user_id = member.user.id

        cls.create(guild_id=guild.id,
                   user_id=user_id,
                   actor_id=event.author.id,
                   type_=cls.Types.WARNING,
                   reason=reason)

        plugin.call('ModLogPlugin.log_action_ext',
                    Actions.MEMBER_WARNED,
                    event.guild.id,
                    member=member,
                    actor=event.author
                    if event.author.id != member.id else 'Automatic',
                    reason=reason or 'no reason')

    @classmethod
    def mute(cls, plugin, event, member, reason):
        from rowboat.plugins.modlog import Actions
        admin_config = cls.admin_config(event)

        if not admin_config.mute_role:
            plugin.log.warning('Cannot mute member {}, no mute role'.format(
                member.id))
            return

        plugin.call(
            'ModLogPlugin.create_debounce',
            event,
            ['GuildMemberUpdate'],
            user_id=member.user.id,
            role_id=admin_config.mute_role,
        )

        member.add_role(admin_config.mute_role, reason=reason)

        plugin.call('ModLogPlugin.log_action_ext',
                    Actions.MEMBER_MUTED,
                    event.guild.id,
                    member=member,
                    actor=event.author
                    if event.author.id != member.id else 'Automatic',
                    reason=reason or 'no reason')

        cls.create(guild_id=event.guild.id,
                   user_id=member.user.id,
                   actor_id=event.author.id,
                   type_=cls.Types.MUTE,
                   reason=reason,
                   metadata={'role': admin_config.mute_role})

    @classmethod
    def tempmute(cls, plugin, event, member, reason, expires_at):
        from rowboat.plugins.modlog import Actions
        admin_config = cls.admin_config(event)

        if not admin_config.mute_role:
            plugin.log.warning(
                'Cannot tempmute member {}, no mute role'.format(member.id))
            return

        plugin.call(
            'ModLogPlugin.create_debounce',
            event,
            ['GuildMemberUpdate'],
            user_id=member.user.id,
            role_id=admin_config.mute_role,
        )

        member.add_role(admin_config.mute_role, reason=reason)

        plugin.call(
            'ModLogPlugin.log_action_ext',
            Actions.MEMBER_TEMP_MUTED,
            event.guild.id,
            member=member,
            actor=event.author
            if event.author.id != member.id else 'Automatic',
            reason=reason or 'no reason',
            expires=expires_at,
        )

        cls.create(guild_id=event.guild.id,
                   user_id=member.user.id,
                   actor_id=event.author.id,
                   type_=cls.Types.TEMPMUTE,
                   reason=reason,
                   expires_at=expires_at,
                   metadata={'role': admin_config.mute_role})

    @classmethod
    def clear_active(cls, event, user_id, types):
        """
        Marks a previously active tempmute as inactive for the given event/user.
        This should be used in all locations where we either think this is no
        longer active (e.g. the mute role was removed) _or_ when we don't want to
        unmute the user any longer, e.g. they've been remuted by another command.
        """
        return cls.update(active=False).where(
            (cls.guild_id == event.guild.id) & (cls.user_id == user_id)
            & (cls.type_ << types) & (cls.active == 1)).execute() >= 1
Exemple #19
0
class Guild(ModelBase):
    WhitelistFlags = Enum('MODLOG_CUSTOM_FORMAT', bitmask=False)

    guild_id = BigIntegerField(primary_key=True)
    owner_id = BigIntegerField(null=True)
    name = TextField(null=True)
    icon = TextField(null=True)
    splash = TextField(null=True)
    region = TextField(null=True)

    last_ban_sync = DateTimeField(null=True)

    # Rowboat specific data
    config = BinaryJSONField(null=True)
    config_raw = BlobField(null=True)

    enabled = BooleanField(default=True)
    whitelist = BinaryJSONField(default=[])

    added_at = DateTimeField(default=datetime.utcnow)

    # SQL = '''
    #     CREATE OR REPLACE FUNCTION shard (int, bigint)
    #     RETURNS bigint AS $$
    #       SELECT ($2 >> 22) % $1
    #     $$ LANGUAGE SQL;
    # '''

    class Meta:
        table_name = 'guilds'

    @classmethod
    def with_id(cls, guild_id):
        return cls.get(guild_id=guild_id)

    @classmethod
    def setup(cls, guild):
        return cls.create(guild_id=guild.id,
                          owner_id=guild.owner_id,
                          name=guild.name,
                          icon=guild.icon,
                          splash=guild.splash,
                          region=guild.region,
                          config={'web': {
                              guild.owner_id: 'admin'
                          }},
                          config_raw='')

    def is_whitelisted(self, flag):
        return int(flag) in self.whitelist

    def update_config(self, actor_id, raw):
        from rowboat.types.guild import GuildConfig

        parsed = yaml.safe_load(raw)
        GuildConfig(parsed).validate()

        GuildConfigChange.create(user_id=actor_id,
                                 guild_id=self.guild_id,
                                 before_raw=self.config_raw,
                                 after_raw=raw)

        self.update(
            config=parsed,
            config_raw=raw).where(Guild.guild_id == self.guild_id).execute()
        self.emit_update()

    def emit_update(self):
        emit('GUILD_UPDATE', id=self.guild_id)

    def sync(self, guild):
        updates = {}

        for key in ['owner_id', 'name', 'icon', 'splash', 'region']:
            if getattr(guild, key) != getattr(self, key):
                updates[key] = getattr(guild, key)

        if updates:
            Guild.update(**updates).where(
                Guild.guild_id == self.guild_id).execute()

    def get_config(self, refresh=False):
        from rowboat.types.guild import GuildConfig

        if refresh:
            self.config = Guild.select(Guild.config).where(
                Guild.guild_id == self.guild_id).get().config

        if refresh or not hasattr(self, '_cached_config'):
            try:
                self._cached_config = GuildConfig(self.config)
            except:
                log.exception('Failed to load config for Guild %s, invalid: ',
                              self.guild_id)
                return None

        return self._cached_config

    def sync_bans(self, guild):
        # Update last synced time
        Guild.update(last_ban_sync=datetime.utcnow()).where(
            Guild.guild_id == self.guild_id).execute()

        try:
            bans = guild.get_bans()
        except:
            log.exception('sync_bans failed for Guild %s', self.guild_id)
            return

        log.info('Syncing %s bans for guild %s', len(bans), guild.id)

        GuildBan.delete().where((~(GuildBan.user_id << list(bans.keys())))
                                & (GuildBan.guild_id == guild.id)).execute()

        for ban in list(bans.values()):
            GuildBan.ensure(guild, ban.user, ban.reason)

    def serialize(self):
        base = {
            'id': str(self.guild_id),
            'owner_id': str(self.owner_id),
            'name': self.name,
            'icon': self.icon,
            'splash': self.splash,
            'region': self.region,
            'enabled': self.enabled,
            'whitelist': self.whitelist
        }

        if hasattr(self, 'role'):
            base['role'] = self.role

        return base
Exemple #20
0
from holster.enum import Enum, EnumAttr

Permissions = Enum(
    CREATE_INSTANT_INVITE=1 << 0,
    KICK_MEMBERS=1 << 1,
    BAN_MEMBERS=1 << 2,
    ADMINISTRATOR=1 << 3,
    MANAGE_CHANNELS=1 << 4,
    MANAGE_GUILD=1 << 5,
    READ_MESSAGES=1 << 10,
    SEND_MESSAGES=1 << 11,
    SEND_TSS_MESSAGES=1 << 12,
    MANAGE_MESSAGES=1 << 13,
    EMBED_LINKS=1 << 14,
    ATTACH_FILES=1 << 15,
    READ_MESSAGE_HISTORY=1 << 16,
    MENTION_EVERYONE=1 << 17,
    USE_EXTERNAL_EMOJIS=1 << 18,
    CONNECT=1 << 20,
    SPEAK=1 << 21,
    MUTE_MEMBERS=1 << 22,
    DEAFEN_MEMBERS=1 << 23,
    MOVE_MEMBERS=1 << 24,
    USE_VAD=1 << 25,
    CHANGE_NICKNAME=1 << 26,
    MANAGE_NICKNAMES=1 << 27,
    MANAGE_ROLES=1 << 28,
    MANAGE_WEBHOOKS=1 << 29,
    MANAGE_EMOJIS=1 << 30,
)

Exemple #21
0
            func.restype = item[1]

            setattr(self, name, func)

    @staticmethod
    def find_library():
        if sys.platform == 'win32':
            raise Exception('Cannot auto-load opus on Windows, please specify full library path')

        return ctypes.util.find_library('opus')


Application = Enum(
    AUDIO=2049,
    VOIP=2048,
    LOWDELAY=2051
)


Control = Enum(
    SET_BITRATE=4002,
    SET_BANDWIDTH=4008,
    SET_FEC=4012,
    SET_PLP=4014,
)


class OpusEncoder(BaseOpus):
    EXPORTED = {
        'opus_encoder_get_size': ([ctypes.c_int], ctypes.c_int),
Exemple #22
0
from holster.enum import Enum

from disco.bot.parser import ArgumentSet, ArgumentError
from disco.util.functional import cached_property

ARGS_REGEX = '(?: ((?:\n|.)*)$|$)'

USER_MENTION_RE = re.compile('<@!?([0-9]+)>')
ROLE_MENTION_RE = re.compile('<@&([0-9]+)>')
CHANNEL_MENTION_RE = re.compile('<#([0-9]+)>')

CommandLevels = Enum(
    DEFAULT=0,
    TRUSTED=10,
    MOD=50,
    ADMIN=100,
    OWNER=500,
)


class CommandEvent(object):
    """
    An event which is created when a command is triggered. Contains information
    about the message, command, and parsed arguments (along with shortcuts to
    message information).

    Attributes
    ---------
    command : :class:`Command`
        The command this event was created for (aka the triggered command).
Exemple #23
0
import requests
import random
import gevent
import six

from holster.enum import Enum

from disco.util.logging import LoggingClass
from disco.api.ratelimit import RateLimiter

# Enum of all HTTP methods used
HTTPMethod = Enum(
    GET='GET',
    POST='POST',
    PUT='PUT',
    PATCH='PATCH',
    DELETE='DELETE',
)


def to_bytes(obj):
    if isinstance(obj, six.text_type):
        return obj.encode('utf-8')
    return obj


class Routes(object):
    """
    Simple Python object-enum of all method/url route combinations available to
    this client.
    """
Exemple #24
0
import six

from holster.enum import Enum

from disco.util.snowflake import to_snowflake
from disco.util.functional import cached_property, one_or_many, chunks
from disco.types.user import User
from disco.types.base import SlottedModel, Field, ListField, AutoDictField, snowflake, enum, text
from disco.types.permissions import Permissions, Permissible, PermissionValue
from disco.voice.client import VoiceClient

ChannelType = Enum(
    GUILD_TEXT=0,
    DM=1,
    GUILD_VOICE=2,
    GROUP_DM=3,
)

PermissionOverwriteType = Enum(ROLE='role', MEMBER='member')


class ChannelSubType(SlottedModel):
    channel_id = Field(None)

    @cached_property
    def channel(self):
        return self.client.state.channels.get(self.channel_id)


class PermissionOverwrite(ChannelSubType):
    """