diff --git a/bot/cogs/contest.py b/bot/cogs/contest.py index faadd2b..72151d3 100644 --- a/bot/cogs/contest.py +++ b/bot/cogs/contest.py @@ -1,5 +1,4 @@ import logging -from datetime import datetime import discord from discord.ext import commands @@ -7,7 +6,7 @@ from discord.ext.commands import Context from bot import checks, constants from bot.bot import ContestBot -from bot.db import Period +from bot.models import Guild, Period, PeriodStates, Submission logger = logging.getLogger(__file__) logger.setLevel(constants.LOGGING_LEVEL) @@ -24,61 +23,75 @@ class ContestCog(commands.Cog): @checks.privileged() async def prefix(self, ctx, new_prefix: str): """Changes the bot's saved prefix.""" - guild = await self.bot.db.get_guild(ctx.guild.id) - if 1 <= len(new_prefix) <= 2: - if guild.prefix == new_prefix: - return await ctx.send(f':no_entry_sign: The prefix is already `{new_prefix}`.') + with self.bot.get_session() as session: + guild = session.query(Guild).filter_by(id=ctx.guild.id).first() + + if 1 <= len(new_prefix) <= 2: + if guild.prefix == new_prefix: + return await ctx.send(f':no_entry_sign: The prefix is already `{new_prefix}`.') + else: + guild.prefix = new_prefix + return await ctx.send(f':white_check_mark: Prefix changed to `{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.') + 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: Context, new_submission: discord.TextChannel) -> None: """Changes the bot's saved submission channel.""" - guild = await self.bot.db.get_guild(ctx.guild.id) - if guild.submission is not None and guild.submission == new_submission.id: - await ctx.send( - f':no_entry_sign: The submission channel is already set to {new_submission.mention}.') - else: - await self.bot.db.set_submission_channel(ctx.guild.id, new_submission.id) - await ctx.send(f':white_check_mark: Submission channel changed to {new_submission.mention}.') + with self.bot.get_session() as session: + guild = session.query(Guild).filter_by(id=ctx.guild.id).first() + + if guild.submission is not None and guild.submission == new_submission.id: + await ctx.send(f':no_entry_sign: The submission channel is already set to {new_submission.mention}.') + else: + guild.submission_channel = new_submission + await ctx.send(f':white_check_mark: Submission channel changed to {new_submission.mention}.') @commands.command() @commands.guild_only() @checks.privileged() - async def submissions(self, ctx: Context, duration: float = None) -> None: - """Opens up the submissions channel.""" + async def advance(self, ctx: Context, duration: float = None, pingback: bool = True) -> None: + """ + Advance the state of the current period pertaining to this Guild. + + :param ctx: + :param duration: If given, + :param pingback: Whether or not the user should be pinged back when the duration is passed. + """ + assert duration == -1 or duration >= 0, "Duration must" - cur = await self.bot.db.conn.cursor() - try: - period = await self.bot.db.get_current_period(ctx.guild.id) + with self.bot.get_session() as session: + guild: Guild = session.query(Guild).get(ctx.guild.id) + period: Period = guild.current_period - # Handle non-existent or final-state period - if period is None: - new_period = Period(guild=ctx.guild.id, current_state=0, started_at=datetime.now(), voting_at=None, finished_at=None) - await self.bot.db.new_period(new_period) + # Handle non-existent or previously completed period in the current guild + if period is None or not period.active: + session.add(Period(id=ctx.guild.id)) + + # Handle previous period being completed. + elif period.state == PeriodStates.READY: + # TODO: Open the channel to messages + pass # Handle submissions state - elif period.current_state == 0: - await self.bot.db.update(period) + elif period.state == PeriodStates.SUBMISSIONS: + # TODO: Close the channel to messages return # Handle voting state - elif period.current_state == 1: + elif period.state == PeriodStates.PAUSED: + # TODO: Add all reactions to every submission + # TODO: Unlock channel reactions + # TODO: Close channel submissions return # Print period submissions - elif period.current_state == 2: + elif period.state == PeriodStates.VOTING: # TODO: Fetch all submissions related to this period # TODO: Create new period for Guild at return - finally: - await cur.close() - @commands.command() @commands.guild_only() @@ -104,39 +117,47 @@ class ContestCog(commands.Cog): @commands.Cog.listener() async def on_message(self, message: discord.Message): if message.author == self.bot.user or message.author.bot or not message.guild: return - guild = await self.bot.db.get_guild(message.guild.id) - channel: discord.TextChannel = message.channel - if channel.id == guild.submission: - attachments = message.attachments - if len(attachments) == 0: - await message.delete(delay=1) - warning = await channel.send( - f':no_entry_sign: {message.author.mention} Each submission must contain exactly one image.') - await warning.delete(delay=5) - elif len(attachments) > 1: - await message.delete(delay=1) - warning = await channel.send( - f':no_entry_sign: {message.author.mention} Each submission must contain exactly one image.') - await warning.delete(delay=5) - else: - last_submission = await self.bot.db.get_submission(message.guild.id, message.author.id) - if last_submission is not None: - # delete last submission - submission_msg = await channel.fetch_message(last_submission) - if submission_msg is None: - logger.error(f'Unexpected: submission message {last_submission} could not be found.') - else: - await submission_msg.delete() - logger.info(f'Old submission deleted. {last_submission} (Old) -> {message.id} (New)') + with self.bot.get_session() as session: + guild = session.query(Guild).get(message.guild.id) + print(session.query(Guild).all) - # Delete the old submission row - await self.bot.db.conn.execute('''DELETE FROM submission WHERE id = ?''', [last_submission]) - await self.bot.db.conn.commit() + channel: discord.TextChannel = message.channel + if channel.id == guild.submission: + attachments = message.attachments - # Add the new submission row - await self.bot.db.add_submission(message.id, channel.guild.id, message.author.id, message.created_at) - logger.info(f'New submission created ({message.id}).') + # TODO: Do attachment filtering between videos/files/audio etc. + + # Ensure that the submission contains at least one attachment + if len(attachments) == 0: + await message.delete(delay=1) + warning = await channel.send( + f':no_entry_sign: {message.author.mention} Each submission must contain exactly one image.') + await warning.delete(delay=5) + # Ensure the image contains no more than one attachment + elif len(attachments) > 1: + await message.delete(delay=1) + warning = await channel.send( + f':no_entry_sign: {message.author.mention} Each submission must contain exactly one image.') + await warning.delete(delay=5) + else: + last_submission = session.query(Submission).filter_by(id=message.guild.id, user=message.author.id) + if last_submission is not None: + # delete last submission + submission_msg = await channel.fetch_message(last_submission) + if submission_msg is None: + logger.error(f'Unexpected: submission message {last_submission} could not be found.') + else: + await submission_msg.delete() + logger.info(f'Old submission deleted. {last_submission} (Old) -> {message.id} (New)') + + # Delete the old submission row + session.delete(last_submission) + + # Add the new submission row + session.add( + Submission(id=message.id, user=message.author.id, period=guild.current_period, timestamp=message.created_at)) + logger.info(f'New submission created ({message.id}).') @commands.Cog.listener() async def on_raw_message_delete(self, payload: discord.RawMessageDeleteEvent) -> None: @@ -148,22 +169,20 @@ class ContestCog(commands.Cog): expected_deletions.remove(payload.message_id) return - # If the message was cached, check that it's in the correct channel. - if payload.cached_message is not None: - guild = await self.bot.db.get_guild(payload.guild_id) - if payload.cached_message.channel.id != guild.submission: + with self.bot.get_session() as session: + guild: Guild = session.query(Guild).get(payload.guild_id) + + # If the message was cached, check that it's in the correct channel. + if payload.cached_message is not None and payload.cached_message.channel.id != guild.submission_channel: return - cur = await self.bot.db.conn.cursor() - try: - await cur.execute('''DELETE FROM submission WHERE id = ? AND guild = ?''', - [payload.message_id, payload.guild_id]) - if cur.rowcount > 0: - author = payload.cached_message.author.display_name if payload.cached_message is not None else 'Unknown' + submission = session.query(Submission).get(payload.message_id) + if submission is None: + logger.error(f'Submission {payload.message_id} could not be deleted from database as it was not found.') + else: + author: str = payload.cached_message.author.display_name if payload.cached_message is not None else 'Unknown' logger.info(f'Submission {payload.message_id} by {author} deleted by outside source.') - await self.bot.db.conn.commit() - finally: - await cur.close() + session.delete(submission) @commands.Cog.listener() async def on_raw_bulk_message_delete(self, payload: discord.RawBulkMessageDeleteEvent) -> None: