add permission/cooldown checks, implement permission setting logic, fix state not being advanced, fix guild.submission disparity and use proper typehinting to catch errors like this

This commit is contained in:
Xevion
2021-02-13 18:31:38 -06:00
parent 9e889d8c8c
commit 28d7768340
2 changed files with 72 additions and 39 deletions

View File

@@ -2,7 +2,7 @@ import logging
import discord import discord
from discord.ext import commands from discord.ext import commands
from discord.ext.commands import Context from discord.ext.commands import Context, BucketType
from bot import checks, constants from bot import checks, constants
from bot.bot import ContestBot from bot.bot import ContestBot
@@ -43,27 +43,31 @@ class ContestCog(commands.Cog):
"""Changes the bot's saved submission channel.""" """Changes the bot's saved submission channel."""
with self.bot.get_session() as session: with self.bot.get_session() as session:
guild = session.query(Guild).filter_by(id=ctx.guild.id).first() guild: Guild = session.query(Guild).get(ctx.guild.id)
if guild.submission is not None and guild.submission == new_submission.id: if guild.submission_channel is not None and guild.submission_channel == new_submission.id:
await ctx.send(f':no_entry_sign: The submission channel is already set to {new_submission.mention}.') await ctx.send(f':no_entry_sign: The submission channel is already set to {new_submission.mention}.')
else: else:
guild.submission_channel = new_submission # TODO: Add channel permissions resetting/migration
guild.submission_channel = new_submission.id
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}.')
# noinspection PyDunderSlots,PyUnresolvedReferences
@commands.command() @commands.command()
@commands.guild_only() @commands.guild_only()
@commands.bot_has_permissions(send_messages=True, manage_roles=True, add_reactions=True, read_message_history=True)
@commands.cooldown(rate=2, per=5, type=BucketType.guild)
@commands.max_concurrency(1, per=BucketType.guild, wait=False)
@checks.privileged() @checks.privileged()
async def advance(self, ctx: Context, duration: float = None, pingback: bool = True) -> None: async def advance(self, ctx: Context, duration: float = None, pingback: bool = True) -> None:
""" """
Advance the state of the current period pertaining to this Guild. Advance the state of the current period pertaining to this Guild.
:param ctx: :param ctx:
:param duration: If given, :param duration: If given, the advance command will be repeated once more after the duration (in seconds) has passed.
:param pingback: Whether or not the user should be pinged back when the duration is passed. :param pingback: Whether or not the user should be pinged back when the duration is passed.
""" """
if duration is not None: assert duration >= 0, "If specified, duration must be more than or equal to zero."
assert duration == -1 or duration >= 0, "Duration must"
with self.bot.get_session() as session: with self.bot.get_session() as session:
guild: Guild = session.query(Guild).get(ctx.guild.id) guild: Guild = session.query(Guild).get(ctx.guild.id)
@@ -71,41 +75,70 @@ class ContestCog(commands.Cog):
# Handle non-existent or previously completed period in the current guild # Handle non-existent or previously completed period in the current guild
if period is None or not period.active: if period is None or not period.active:
session.add(Period(id=ctx.guild.id)) if period is None:
overwrite = discord.PermissionOverwrite()
overwrite.send_messages = False
overwrite.add_reactions = False
await self.bot.get_channel(guild.submission_channel).set_permissions(ctx.guild.default_role, overwrite=overwrite)
await ctx.send('Period created, channel permissions set.')
# Handle previous period being completed. period = Period(guild_id=guild.id)
elif period.state == PeriodStates.READY: session.add(period)
# TODO: Open the channel to messages session.commit()
pass
# Handle submissions state
elif period.state == PeriodStates.SUBMISSIONS:
# TODO: Close the channel to messages
return
# Handle voting state
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.state == PeriodStates.VOTING:
# TODO: Fetch all submissions related to this period
# TODO: Create new period for Guild at
return
@commands.command() guild.current_period = period
@commands.guild_only() await ctx.send('New period started - submissions and voting disabled.')
@checks.privileged() else:
async def voting(self, ctx: Context, duration: float = None) -> None: channel: discord.TextChannel = self.bot.get_channel(guild.submission_channel)
"""Closes submissions and sets up the voting period.""" target_role: discord.Role = ctx.guild.default_role
if duration < 0: # TODO: Research best way to implement contest roles with vagabondit's input
await ctx.send('Invalid duration - must be non-negative.')
overwrite = discord.PermissionOverwrite()
response = 'Permissions unchanged - Period state error.'
# Handle previous period being completed.
if period.state == PeriodStates.READY:
overwrite.send_messages = True
overwrite.add_reactions = False
response = 'Period started, submissions allowed. Advance again to pause.'
# Handle submissions state
elif period.state == PeriodStates.SUBMISSIONS:
overwrite.send_messages = False
overwrite.add_reactions = False
response = 'Period paused, submissions disabled. Advance again to start voting.'
# Handle voting state
elif period.state == PeriodStates.PAUSED:
# TODO: Add all reactions to every submission
overwrite.send_messages = False
overwrite.add_reactions = True
response = 'Period unpaused, reactions allowed. Advance again to stop voting and finalize the tallying.'
# Print period submissions
elif period.state == PeriodStates.VOTING:
overwrite.send_messages = False
overwrite.add_reactions = False
response = 'Period stopped. Reactions and submissions disabled. Advance again to start a new period.'
# TODO: Fetch all submissions related to this period
# TODO: Create new period for Guild at
period.advance_state()
await channel.set_permissions(target_role, overwrite=overwrite)
await ctx.send(response)
@commands.command() @commands.command()
@commands.guild_only() @commands.guild_only()
@checks.privileged() @checks.privileged()
async def close(self, ctx: Context) -> None: async def close(self, ctx: Context) -> None:
"""Closes the voting period.""" """Closes the current period."""
with self.bot.get_session() as session:
guild: Guild = session.query(Guild).get(ctx.guild.id)
period: Period = guild.current_period
if period is None or not period.active:
await ctx.send('No period is currently active.')
else:
period.deactivate()
await ctx.send('The current period has been closed.')
pass pass
@commands.command() @commands.command()
@@ -119,11 +152,10 @@ class ContestCog(commands.Cog):
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
with self.bot.get_session() as session: with self.bot.get_session() as session:
guild = session.query(Guild).get(message.guild.id) guild: 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_channel:
attachments = message.attachments attachments = message.attachments
# TODO: Do attachment filtering between videos/files/audio etc. # TODO: Do attachment filtering between videos/files/audio etc.

View File

@@ -97,7 +97,7 @@ class Period(Base):
""" """
Advances the current recorded state of this Period, recording timestamps as needed. Advances the current recorded state of this Period, recording timestamps as needed.
""" """
next_state = PeriodStates(int(self.state) + 1) next_state = PeriodStates(self.state.value + 1)
if self.state == PeriodStates.READY: if self.state == PeriodStates.READY:
self.submissions_time = datetime.datetime.utcnow() self.submissions_time = datetime.datetime.utcnow()
elif self.state == PeriodStates.SUBMISSIONS: elif self.state == PeriodStates.SUBMISSIONS:
@@ -109,6 +109,7 @@ class Period(Base):
self.completed = True self.completed = True
self.active = False self.active = False
self.state = next_state
return next_state return next_state
@check_not_finished @check_not_finished