From df85862f1db0dae6193cad4b30d87a6478367137 Mon Sep 17 00:00:00 2001 From: CMDR furrycat Date: Sat, 29 Oct 2016 10:36:19 +0100 Subject: [PATCH] Moved some admin commands to plugin. --- app.py | 63 +++--------------------- bot.py | 17 +++++++ db.py | 3 ++ plugin/admin/admin.py | 133 ++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 159 insertions(+), 57 deletions(-) create mode 100644 plugin/admin/admin.py diff --git a/app.py b/app.py index fa13d99..54771f7 100644 --- a/app.py +++ b/app.py @@ -44,14 +44,6 @@ token_file = 'TOKEN' if len(sys.argv) > 1: token_file = sys.argv[1] -admins = [] -admin_role = 'Cat' -fd = open('ADMINS', 'r') -for line in fd.readlines(): - admin = line.strip() - admins.append(admin) -fd.close() - fd = open(token_file, 'r') token = fd.readline().strip() fd.close() @@ -59,6 +51,7 @@ logging.basicConfig(level = logging.DEBUG if bot.get('debug') else logging.WARN, discordlog = logging.getLogger('discord') log = logging.getLogger('catbot') bot.log = log +bot.db = db log.setLevel(logging.DEBUG if bot.get('debug') else logging.INFO) plugins.log_level(log.level) @@ -83,17 +76,6 @@ def not_admin(message): yield from bot.maybe_say(message.channel, 'hiss!') @asyncio.coroutine -def is_admin(server, member): - if server is None: - return member.id in admins - for role in server.roles: - if role.name != admin_role: - continue - if role in member.roles: - return True - return False - -@asyncio.coroutine def identify(destination, target): do = Identify.member.value | Identify.role.value | Identify.channel.value channel_id = None @@ -248,8 +230,7 @@ def show_help(message, *args): @asyncio.coroutine def do_commands(message, command, raw, non_admin): if not non_admin: - result = yield from is_admin(message.server, message.author) - if not result: + if not bot.is_admin(message.author, message.server): yield from not_admin(message) return @@ -272,25 +253,6 @@ def do_commands(message, command, raw, non_admin): yield from cat.yelp(message.channel) return - elif command == 'debug': - # debug - m = re.match(r'\bdebug\s+(o(?:ff|n))\b', raw, re.IGNORECASE) - if m is None: - yield from bot.say(message.channel, 'Sorry!') - return - - arg = m.group(1) - if arg == 'on': - discordlog.setLevel(logging.DEBUG) - log.setLevel(logging.DEBUG) - db.log_level(logging.DEBUG) - plugins.log_level(logging.DEBUG) - elif arg == 'off': - discordlog.setLevel(logging.WARN) - log.setLevel(logging.INFO) - db.log_level(logging.WARN) - plugins.log_level(logging.INFO) - elif command == 'delete': # delete if message.channel.is_private: @@ -306,21 +268,6 @@ def do_commands(message, command, raw, non_admin): yield from client.purge_from(message.channel, *args, limit = limit) return - elif command == 'dryrun': - # dryrun - m = re.match(r'\bdryrun\s+(o(?:ff|n))\b', raw, re.IGNORECASE) - if m is None: - yield from bot.say(message.channel, 'Sorry!') - return - - arg = m.group(1) - if arg == 'on': - log.info('DRYRUN mode') - bot.set('dryrun', True) - elif arg == 'off': - log.info('Live mode') - bot.set('dryrun', False) - elif command == 'id': # id m = re.match(r'\bid\s+(.*)', raw, re.IGNORECASE) @@ -416,7 +363,7 @@ modules = { 'admin': { 'fn': do_commands, 'args': [False], - 'commands': ['avatar', 'debug', 'delete', 'dryrun', 'idle', 'rss'] + 'commands': ['avatar', 'delete', 'idle', 'rss'] }, 'any': { 'fn': do_commands, @@ -439,6 +386,9 @@ client = discord.Client() bot.client = client bot.db = db plugins.set_client(client) +if 'admin' in plugins.plugins(): + plugins.get_plugin('admin').db = db + plugins.get_plugin('admin').plugins = plugins @asyncio.coroutine def builtin_commands(message, command, raw): @@ -492,7 +442,6 @@ def on_ready(): if state['last_spoke']: bot.set('last_spoke', state['last_spoke']) log.info('Logged in as {}#{}'.format(client.user.name, client.user.id)) - log.info('Admins are: {}'.format(admins)) if not threads_ready.value: plugins.on_ready() asyncio.async(maybe_sleep()) diff --git a/bot.py b/bot.py index ade6c6c..25f11c4 100644 --- a/bot.py +++ b/bot.py @@ -22,6 +22,23 @@ variables = { 'playing': multiprocessing.Value('b', False) } +def is_admin(user, server = None): + ret = False + params = ['global'] + if server is not None: + params.append(server.id) + sql = 'select id from admins where server_id in ({}) and bot_id in (?, ?) and user_id=?'.format(', '.join(['?'] * len(params))) + params.append('global') + params.append(client.user.id) + params.append(user.id) + cursor = db.query(sql, params) + for row in cursor.fetchall(): + ret = True + break + db.close_db() + log.info('User {} {} an administrator{}'.format(user.name, 'is' if ret else 'is not', ' on server {}'.format(server.name) if server is not None else '')) + return ret + def get(key): if key in variables: return variables[key].value diff --git a/db.py b/db.py index c37bd20..16f936e 100644 --- a/db.py +++ b/db.py @@ -33,6 +33,9 @@ class DBConnection(object): cursor = self.query('create table if not exists state (id char(36) not null, bot_id varchar(32) not null, avatar varchar(128), idle boolean not null default false, last_spoke datetime)') cursor = self.query('create unique index if not exists state_id on state (id)') cursor = self.query('create unique index if not exists state_bot_id on state (bot_id)') + cursor = self.query('create table if not exists admins (id char(36) not null, bot_id varchar(32) not null, server_id varchar(32) not null, user_id varchar(32))') + cursor = self.query('create unique index if not exists admins_id on admins (id)') + cursor = self.query('create index if not exists admins_bot_id on admins (bot_id)') self.dbh.commit() self.close_db() diff --git a/plugin/admin/admin.py b/plugin/admin/admin.py new file mode 100644 index 0000000..5e604c3 --- /dev/null +++ b/plugin/admin/admin.py @@ -0,0 +1,133 @@ +import asyncio +import logging +import shlex +import sys + +from plugins import PluginCommand +import bot +import cat + +class Admin(object): + def __init__(self): + self.discordlog = logging.getLogger('discord') + self.botlog = logging.getLogger('catbot') + self.db = None + self.plugins = None + return None + + def description(self): + return 'Lets privileged users manage the bot.' + + def create_tables(self): + self.open_db() + self.dbh.commit() + self.close_db() + + def valid_commands(self): + return ['debug', 'dryrun', 'shutdown'] + + @asyncio.coroutine + def handle_command(self, message, command, raw): + if command not in self.valid_commands(): + return PluginCommand.ignored + yield from self.run_command(message, shlex.split(raw)) + return PluginCommand.exclusive + + @asyncio.coroutine + def handle_help(self, message, command, *args): + yield from self.help_command(message, *args) + + @asyncio.coroutine + def run_command(self, message, args): + if not bot.is_admin(message.author): + yield from cat.hiss(message.channel) + return + + command = args[0] + if command == 'debug': + yield from self.handle_debug(message, args[1:]) + elif command == 'dryrun': + yield from self.handle_dryrun(message, args[1:]) + elif command == 'shutdown': + yield from self.handle_shutdown(message) + + @asyncio.coroutine + def help_command(self, message, command): + if command == 'debug': + lines = [ + 'Turn debugging on or off.', + '```', + 'debug on', + 'debug off', + '```', + '', + 'You will need access to my logs to see the debugging output!' + ] + elif command == 'dryrun': + lines = [ + 'Enable or disable plugins (if supported).', + '```', + 'dryrun on', + 'dryrun off', + '```' + ] + elif command == 'shutdown': + lines = [ + 'Shut the bot down!', + '```shutdown```' + ] + else: + lines = ['*shrugs*'] + yield from bot.say_many(message.channel, lines) + + @asyncio.coroutine + def handle_debug(self, message, args): + if len(args): + arg = args[0].lower() + if arg == 'on': + self.discordlog.setLevel(logging.DEBUG) + self.botlog.setLevel(logging.DEBUG) + if self.db is not None: + self.db.log_level(logging.DEBUG) + if self.plugins is not None: + self.plugins.log_level(logging.DEBUG) + elif arg == 'off': + self.discordlog.setLevel(logging.WARN) + self.botlog.setLevel(logging.INFO) + if self.db is not None: + self.dblog.log_level(logging.WARN) + if self.plugins is not None: + self.plugins.log_level(logging.INFO) + else: + yield from cat.yelp(message.channel) + return + yield from bot.maybe_say(message.channel, 'purr', wake = False) + else: + yield from cat.yelp(message.channel) + + @asyncio.coroutine + def handle_dryrun(self, message, args): + if len(args): + arg = args[0].lower() + if arg == 'on': + log.info('DRYRUN mode.') + bot.set('dryrun', True) + elif arg == 'off': + log.info('Live mode.') + bot.set('dryrun', False) + else: + yield from cat.yelp(message.channel) + return + yield from bot.maybe_say(message.channel, 'purr', wake = False) + else: + yield from cat.yelp(message.channel) + + @asyncio.coroutine + def handle_shutdown(self, message): + log.warning('Shutdown initiated!') + result = yield from bot.say(message.channel, 'Goodbye!') + result = yield from client.logout() + try: + sys.exit(0) + except: + pass -- 2.7.4