fully re-implement contest cog with sqlalchemy, begin planning proper period logic in TODOs

This commit is contained in:
Xevion
2021-02-13 08:28:57 -06:00
parent 5978068e9b
commit ca10389aea

View File

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