diff --git a/contest/bot.py b/contest/bot.py new file mode 100644 index 0000000..a5aa34e --- /dev/null +++ b/contest/bot.py @@ -0,0 +1,44 @@ +import logging +from typing import Optional + +import discord +from discord.ext import commands + +from contest import constants +from contest.db import ContestDatabase + +logger = logging.getLogger(__file__) +logger.setLevel(constants.LOGGING_LEVEL) + + +async def fetch_prefix(bot: 'ContestBot', message: discord.Message): + """Fetches the prefix used by the relevant guild.""" + user_id = bot.user.id + base = [f'<@!{user_id}> ', f'<@{user_id}> '] + + if message.guild: + if bot.db is not None: + base.append(await bot.db.get_prefix(message.guild.id)) + return base + + +class ContestBot(commands.Bot): + def __init__(self, **options): + self.db: Optional[ContestDatabase] = None + super().__init__(fetch_prefix, **options) + + async def on_ready(self): + if self.db is None: + self.db = await ContestDatabase.create() + logger.info('Bot is now ready and connected to Discord.') + guild_count = len(self.guilds) + logger.info( + f'Connected as {self.user.name}#{self.user.discriminator} to {guild_count} guild{"s" if guild_count > 1 else ""}.') + + async def on_guild_join(self, guild: discord.Guild) -> None: + logger.info(f'Added to new guild: {guild.name} ({guild.id})') + await self.db.setup_guild(guild.id) + + async def on_guild_remove(self, guild: discord.Guild) -> None: + logger.info(f'Removed from guild: {guild.name} ({guild.id})') + await self.db.teardown_guild(guild.id) diff --git a/contest/client.py b/contest/client.py deleted file mode 100644 index 5656255..0000000 --- a/contest/client.py +++ /dev/null @@ -1,60 +0,0 @@ -import logging -import re -from typing import Optional - -import discord as discord - -from contest import constants -from contest.db import ContestDatabase - -logger = logging.getLogger(__file__) -logger.setLevel(constants.LOGGING_LEVEL) - - -class ContestClient(discord.Client): - def __init__(self, **options) -> None: - super().__init__(**options) - self.db: Optional[ContestDatabase] = None - - async def on_guild_join(self, guild: discord.Guild) -> None: - logger.info(f'Added to new guild: {guild.name} ({guild.id})') - await self.db.setup_guild(guild.id) - - async def on_guild_remove(self, guild: discord.Guild) -> None: - logger.info(f'Removed from guild: {guild.name} ({guild.id})') - await self.db.teardown_guild(guild.id) - - async def on_ready(self): - await self.wait_until_ready() - logger.info('Bot is now ready and connected to Discord.') - guild_count = len(self.guilds) - logger.info( - f'Connected as {self.user.name}#{self.user.discriminator} to {guild_count} guild{"s" if guild_count > 1 else ""}.') - self.db = await ContestDatabase.create() - - async def on_message(self, message: discord.Message) -> None: - # Ignore self + bots - if message.author == self.user or message.author.bot: - return - - # Compile a regex made for parsing commands - prefix = await self.db.get_prefix(message.guild.id) - if message.content.startswith(prefix) and len(message.content) > 1: - split = message.content[1:].split() - command = split[0] - args = split[1:] - - await message.channel.send(content=f'{command} {args}') - - - async def on_raw_reaction_add(self, payload: discord.RawReactionActionEvent) -> None: - pass - - async def on_raw_reaction_remove(self, payload: discord.RawReactionActionEvent) -> None: - pass - - async def on_raw_reaction_clear(self, payload: discord.RawReactionActionEvent) -> None: - pass - - async def on_raw_reaction_clear_emoji(self, payload: discord.RawReactionClearEmojiEvent) -> None: - pass diff --git a/contest/cogs/contest.py b/contest/cogs/contest.py new file mode 100644 index 0000000..1bc1b62 --- /dev/null +++ b/contest/cogs/contest.py @@ -0,0 +1,53 @@ +import discord +from discord.ext import commands + +from contest import checks +from contest.bot import ContestBot + + +class ContestCog(commands.Cog): + def __init__(self, bot: ContestBot): + self.bot = bot + + @commands.command() + @commands.guild_only() + @checks.privileged() + async def prefix(self, ctx, new_prefix: str): + """Changes the bot's saved prefix.""" + cur_prefix = await self.bot.db.get_prefix(ctx.guild.id) + if 1 <= len(new_prefix) <= 2: + if cur_prefix == new_prefix: + return await ctx.send(f'The prefix is already `{new_prefix}`') + else: + await self.bot.db.set_prefix(ctx.guild.id, new_prefix) + return await ctx.send(f':white_check_mark: Prefix changed to `{new_prefix}`') + else: + return await ctx.send(':no_entry_sign: Invalid argument. Prefix must be 1 or 2 characters long.') + + @commands.command() + @commands.guild_only() + @checks.privileged() + async def submission(self, ctx, new_submission: discord.TextChannel): + """Changes the bot's saved submission channel.""" + pass + + + @commands.Cog.listener() + async def on_raw_reaction_add(self, payload: discord.RawReactionActionEvent) -> None: + pass + + @commands.Cog.listener() + async def on_raw_reaction_remove(self, payload: discord.RawReactionActionEvent) -> None: + pass + + @commands.Cog.listener() + async def on_raw_reaction_clear(self, payload: discord.RawReactionActionEvent) -> None: + pass + + @commands.Cog.listener() + async def on_raw_reaction_clear_emoji(self, payload: discord.RawReactionClearEmojiEvent) -> None: + pass + + +def setup(bot) -> None: + bot.add_cog(ContestCog(bot)) diff --git a/main.py b/main.py index 5ed57a0..6722686 100644 --- a/main.py +++ b/main.py @@ -1,19 +1,26 @@ import logging -from contest import client, constants +from contest import constants +from contest.bot import ContestBot if __name__ == "__main__": - bot = client.ContestClient() - logger = logging.getLogger(__file__) logger.setLevel(constants.LOGGING_LEVEL) + # noinspection PyArgumentList logging.basicConfig(format='[%(asctime)s] [%(levelname)s] [%(funcName)s] %(message)s', handlers=[ logging.FileHandler(f"bot.log", encoding='utf-8'), logging.StreamHandler() ]) - logger.info('Starting bot.') + initial_extensions = ['contest.cogs.contest'] + + bot = ContestBot(description='A assistant for the Photography Lounge\'s monday contests') + + for extension in initial_extensions: + bot.load_extension(extension) + + logger.info('Starting bot...') with open('token.dat', 'r') as file: - bot.run(file.read()) + bot.run(file.read(), bot=True, reconnect=True)