Beispiel #1
0
    def __init__(self, in_bot=True):
        self.plugin_db = PrefixedRedis(self.db, 'plugin.' + self.id + '.')

        self.in_bot = in_bot

        methods = inspect.getmembers(self, predicate=inspect.ismethod)
        commands_callbacks = [
            meth for name, meth in methods if get(meth, 'command_info')
        ]
        self.commands = []
        for cb in commands_callbacks:
            info = cb.command_info

            opts = dict()
            opts['expression'] = info['expression']
            opts['description'] = info['description']
            opts['callback'] = cb
            opts['plugin'] = self
            opts['restrict_default'] = info.get('restrict_default', False)

            command = Command(**opts)
            self.commands.append(command)

        # Configs group keys
        self.config_db = GroupKeys(self.id + '.config',
                                   self.plugin_db,
                                   cache=in_bot,
                                   callback=self.handle_config_change)

        # Commands Configs group keys
        self.commands_config_db = GroupKeys(
            self.id + '.cmd-config',
            self.plugin_db,
            cache=in_bot,
            callback=self.handle_commands_config_change)
Beispiel #2
0
    def get_guild_storage(self, guild):
        guild_id = get(guild, 'id', guild)
        guild_storage = self.guild_storages.get(guild_id)

        if guild_storage:
            return guild_storage

        prefix = 'plugin.{}.guild.{}.storage.'.format(self.id, guild_id)
        guild_storage = PrefixedRedis(self.db, prefix)
        self.guild_storages[guild_id] = guild_storage

        return guild_storage
Beispiel #3
0
    def __init__(self,
                 expression=None,
                 callback=None,
                 require_roles=[],
                 description="",
                 after_check=lambda _, __: True,
                 plugin=None,
                 restrict_default=False):
        self.name = callback.__name__
        self.id = 'command.{}.{}'.format(plugin.id, self.name)
        self.expression = expression
        self.callback = callback
        self.require_roles = require_roles
        self.description = description
        self.regex, self.cast_to = build_regex(self.expression)
        self.after_check = after_check
        self.restrict_default = restrict_default

        self.plugin = plugin

        self.command_db = PrefixedRedis(plugin.db, self.id + '.')
        self.config_db = GroupKeys(self.id + '.config',
                                   self.command_db,
                                   cache=plugin.in_bot)
Beispiel #4
0
class Command:
    @classmethod
    def register(cls, expression):
        def deco(f):
            command_info = {
                'expression': expression,
                'callback': f,
                'description': ''
            }
            f.command_info = command_info
            return f

        return deco

    @classmethod
    def description(cls, description):
        def deco(f):
            f.command_info['description'] = description
            return f

        return deco

    @classmethod
    def restrict_default(cls, f):
        f.command_info['restrict_default'] = True
        return f

    def to_dict(self, guild_id=None):
        dct = {
            'id': self.id,
            'name': self.name,
            'description': self.description,
            '_expression': self.expression
        }

        if guild_id is not None:
            dct['config'] = self.get_config(guild_id).serialize()

        return dct

    def __init__(self,
                 expression=None,
                 callback=None,
                 require_roles=[],
                 description="",
                 after_check=lambda _, __: True,
                 plugin=None,
                 restrict_default=False):
        self.name = callback.__name__
        self.id = 'command.{}.{}'.format(plugin.id, self.name)
        self.expression = expression
        self.callback = callback
        self.require_roles = require_roles
        self.description = description
        self.regex, self.cast_to = build_regex(self.expression)
        self.after_check = after_check
        self.restrict_default = restrict_default

        self.plugin = plugin

        self.command_db = PrefixedRedis(plugin.db, self.id + '.')
        self.config_db = GroupKeys(self.id + '.config',
                                   self.command_db,
                                   cache=plugin.in_bot)

    def default_config(self, guild):
        guild_id = get(guild, 'id', guild)

        default_config = {
            'allowed_roles': [],
            'enabled': True,
            'global_cooldown': -1,
            'personal_cooldown': -1
        }

        if not self.restrict_default:
            default_config['allowed_roles'] = [guild_id]

        return CommandConfig(**default_config)

    def get_config(self, guild):
        guild_id = get(guild, 'id', guild)

        raw_config = self.config_db.get('config.{}'.format(guild_id))
        if raw_config is None:
            return self.default_config(guild)

        config = json.loads(raw_config)
        return CommandConfig(**config)

    def patch_config(self, guild, partial_new_config):
        guild_id = get(guild, 'id', guild)
        config = self.get_config(guild)
        for field_name in config.__class__._fields:
            new_value = partial_new_config.get(field_name)
            if new_value is not None:
                setattr(config, field_name, new_value)
        config.sanitize()
        config.validate()
        raw_config = json.dumps(config.serialize())
        self.config_db.set('config.{}'.format(guild_id), raw_config)
        return config

    def delete_config(self, guild):
        guild_id = get(guild, 'id', guild)
        self.config_db.delete('config.{}'.format(guild_id))

    def check_permission(self, ctx):
        member_permissions = ctx.author.guild_permissions

        if (member_permissions >> 5 & 1) or (member_permissions >> 3 & 1):
            return True

        if int(ctx.author.id) == int(ctx.guild.owner_id):
            return True

        config = self.get_config(ctx.guild)
        allowed_roles = config.allowed_roles
        for role in ctx.author.roles:
            role_id = get(role, 'id', role)
            if role_id in allowed_roles:
                return True

        return False

    def check_enabled(self, ctx):
        config = self.get_config(ctx.guild)
        return config.enabled

    def check_cooldown(self, ctx):
        config = self.get_config(ctx.guild)

        global_cooldown = config.global_cooldown
        if global_cooldown > -1:
            key = 'cooldown.{}'.format(ctx.guild.id)
            cd_check = self.command_db.get(key)
            if cb_check:
                return False

            self.command_db.setex(key, 1, global_cooldown)

        personal_cooldown = config.personal_cooldown
        if global_cooldown > -1:
            key = 'cooldown.{}.{}'.format(ctx.guild.id, ctx.author.id)
            cd_check = self.command_db.get(key)
            if cb_check:
                return False

            self.command_db.setex(key, 1, personal_cooldown)

        return True

    def check_match(self, msg):
        match = self.regex.match(msg)
        if not match:
            return None

        return CommandMatch(self, match)

    def execute(self, guild, message):
        match = self.check_match(message.content)
        if match is None:
            return

        ctx = CommandContext(guild, message)

        if not self.check_permission(ctx):
            return

        if not self.check_enabled(ctx):
            return

        if not self.check_cooldown(ctx):
            return

        if not self.after_check(self, ctx):
            return

        try:
            response = self.callback(ctx, *match.arguments)
        except Exception as e:
            response = Response.internal_error()
            traceback.print_exc()

        if response:
            return response.send(guild, message.channel_id)