async def __safe_alter_config(client: bot.Overlord, path: str, value): parent_config = client.config.parent() try: old_value = parent_config[path] except KeyError: log.info(f'Invalid config path provided: {path}') await client.control_channel.send( res.get("messages.invalid_config_path")) return False try: log.warn(f'Altering raw config path {path}') parent_config.alter(path, value) if parent_config['logger']: logging.config.dictConfig(parent_config['logger']) client.update_config(parent_config.bot) except (InvalidConfigException, TypeError) as e: log.warn( f'Invalid config value provided: {value}, reason: {e}. Reverting.') parent_config.alter(path, old_value) if parent_config['logger']: logging.config.dictConfig(parent_config['logger']) client.update_config(parent_config.bot) msg = res.get("messages.error").format(e) + '\n' + res.get( "messages.warning").format('Config reverted') await client.control_channel.send(msg) return False return True
def main(argv): # Load env variables load_dotenv() # Parse arguments parser = argparse.ArgumentParser(description='Overlord Discord Bot') parser.add_argument('-c', '--config', nargs='?', type=str, default='config.json', help='config path') args = parser.parse_args(argv[1:]) # Load config config = ConfigView(path=args.config, schema_name="config_schema") # Apply logging config if config['logger']: logging.config.dictConfig(config['logger']) # Init database url = os.getenv('DATABASE_ACCESS_URL') if 'sqlite' in url: import db.queries as q q.MODE = q.MODE_SQLITE session = DBSession(url, autocommit=False) session.sync_table(EventType, 'name', EVENT_TYPES) session.sync_table(UserStatType, 'name', USER_STAT_TYPES) # Init bot discord_bot = Overlord(config.bot, session) discord_bot.run() return 0
async def reload_config(client: bot.Overlord, msg: discord.Message): log.info(f'Reloading config') # Reload config parent_config = client.config.parent() new_config = ConfigView(path=parent_config.fpath(), schema_name="config_schema") if new_config['logger']: logging.config.dictConfig(new_config['logger']) client.update_config(new_config.bot) log.info(f'Done') await client.control_channel.send(res.get("messages.done"))
async def update_user_rank(client: bot.Overlord, msg: discord.Message, member: discord.Member): async with client.sync(): await msg.channel.send( res.get("messages.update_rank_begin").format(member.mention)) await client.update_user_rank(member) await msg.channel.send(res.get("messages.done"))
async def clear_data(client: bot.Overlord, msg: discord.Message): models = [ db.MemberEvent, db.MessageEvent, db.VoiceChatEvent, db.UserStat, db.User, db.Role ] table_data_drop = res.get("messages.table_data_drop") # Tranaction begins async with client.sync(): log.warn("Clearing database") await client.send_warning("Clearing database") for model in models: log.warn(f"Clearing table `{model.table_name()}`") await client.control_channel.send( table_data_drop.format(model.table_name())) client.db.query(model).delete() client.db.commit() client.set_awaiting_sync() log.info(f'Done') await client.control_channel.send(res.get("messages.done"))
async def recalculate_stats(client: bot.Overlord, msg: discord.Message): # Tranaction begins async with client.sync(): log.info(f"Recalculating all stats") answer = res.get("messages.user_stat_calc") await msg.channel.send(answer.format('all')) for stat_type in client.s_stats.user_stat_type_map: client.s_stats.reload_stat(stat_type) log.info(f'Done') await msg.channel.send(res.get("messages.done"))
async def remove_rank(client: bot.Overlord, msg: discord.Message, role_name: str): role = client.get_role(role_name) if role is None: await msg.channel.send( res.get("messages.rank_role_unknown").format(role_name)) return ranks = client.config.ranks.role.copy().value() if role_name not in ranks: await msg.channel.send(res.get("messages.rank_unknown")) return del ranks[role_name] path = 'bot.ranks.role' if await __safe_alter_config(client, path, ranks): __save_config(client) log.info(f'Done') await client.control_channel.send(res.get("messages.done"))
async def reload_channel_history(client: bot.Overlord, msg: discord.Message, channel: discord.TextChannel): permissions = channel.permissions_for(client.me) if not permissions.read_message_history: answer = res.get("messages.missing_access").format( channel.mention) + ' (can\'t read message history)' await msg.channel.send(answer) return # Tranaction begins async with client.sync(): # Drop full channel message history log.warn(f'Dropping #{channel.name}({channel.id}) history') answer = res.get("messages.channel_history_drop").format( channel.mention) await msg.channel.send(answer) client.s_events.clear_text_channel_history(channel) # Load all messages log.warn(f'Loading #{channel.name}({channel.id}) history') answer = res.get("messages.channel_history_load").format( channel.mention) await msg.channel.send(answer) async for message in channel.history(limit=None, oldest_first=True): # Skip bot messages if message.author.bot: continue # Resolve user user = client.s_users.get(message.author) if user is None and client.config["user.leave.keep"]: user = client.s_users.add_user(message.author) # Skip users not in db if user is None: continue # Insert new message event client.s_events.create_new_message_event(user, message) log.info(f'Done') await msg.channel.send(res.get("messages.done"))
async def edit_rank(client: bot.Overlord, msg: discord.Message, role_name: str, weight: str, membership: str, msg_count: str, vc_time: str): try: weight = int(weight) membership = int(membership) messages_count = int(msg_count) vc_time = int(vc_time) except ValueError: await msg.channel.send(res.get("messages.rank_arg_parse_error")) return role = client.get_role(role_name) if role is None: await msg.channel.send( res.get("messages.rank_role_unknown").format(role_name)) return ranks = client.config.ranks.role.copy().value() if role_name not in ranks: await msg.channel.send(res.get("messages.rank_unknown")) return ranks_weights = {ranks[r]['weight']: r for r in ranks} if weight in ranks_weights and ranks_weights[weight] != role_name: await msg.channel.send( res.get("messages.rank_role_same_weight").format( ranks_weights[weight])) return ranks[role_name] = { "weight": weight, "membership": membership, "messages": messages_count, "vc": vc_time } path = 'bot.ranks.role' if await __safe_alter_config(client, path, ranks): __save_config(client) log.info(f'Done') await client.control_channel.send(res.get("messages.done"))
async def update_user_ranks(client: bot.Overlord, msg: discord.Message): async with client.sync(): await msg.channel.send(res.get("messages.update_ranks_begin")) await client.update_user_ranks() await msg.channel.send(res.get("messages.done"))
async def sync_roles(client: bot.Overlord, msg: discord.Message): async with client.sync(): await msg.channel.send(res.get("messages.sync_users_begin")) await client.sync_users() await msg.channel.send(res.get("messages.done"))
async def ping(client: bot.Overlord, msg: discord.Message): if client.sync().locked(): await msg.channel.send(res.get("messages.busy")) else: await msg.channel.send(res.get("messages.pong"))