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