diff --git a/bot/cogs/contest_commands.py b/bot/cogs/contest_commands.py index 86920c7..576338c 100644 --- a/bot/cogs/contest_commands.py +++ b/bot/cogs/contest_commands.py @@ -5,7 +5,7 @@ import discord from discord.ext import commands from discord.ext.commands import BucketType, Context, errors -from bot import checks, constants +from bot import checks, constants, helpers from bot.bot import ContestBot from bot.models import Guild, Period, PeriodStates, Submission @@ -13,9 +13,9 @@ logger = logging.getLogger(__file__) logger.setLevel(constants.LOGGING_LEVEL) -class ContestCommandsCog(commands.Cog): +class ContestCommandsCog(commands.Cog, name='Contest'): """ - Manages all commands related to contests. + Commands related to creating, advancing, and querying contests. """ def __init__(self, bot: ContestBot) -> None: @@ -32,12 +32,13 @@ class ContestCommandsCog(commands.Cog): 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}`.') + return await ctx.send(embed=helpers.error_embed(message=f'The prefix is already `{new_prefix}`.')) else: guild.prefix = new_prefix - return await ctx.send(f':white_check_mark: Prefix changed to `{new_prefix}`.') + return await ctx.send(embed=helpers.success_embed(message=f'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(embed=helpers.error_embed( + message='Invalid argument. Prefix must be 1 or 2 characters long.')) @commands.command() @commands.guild_only() @@ -49,11 +50,14 @@ class ContestCommandsCog(commands.Cog): guild: Guild = session.query(Guild).get(ctx.guild.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(embed=helpers.error_embed( + message=f'The submission channel is already set to {new_submission.mention}.')) else: # 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(embed=helpers.success_embed( + message=f':white_check_mark: Submission channel changed to {new_submission.mention}.' + )) # noinspection PyDunderSlots,PyUnresolvedReferences @commands.command() @@ -83,14 +87,14 @@ class ContestCommandsCog(commands.Cog): 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.') + await ctx.send(embed=helpers.success_embed(message='Period created, channel permissions set.')) period = Period(guild_id=guild.id) session.add(period) session.commit() guild.current_period = period - await ctx.send('New period started - submissions and voting disabled.') + await ctx.send(embed=helpers.success_embed(message='New period started - submissions and voting disabled.')) else: channel: discord.TextChannel = self.bot.get_channel(guild.submission_channel) target_role: discord.Role = ctx.guild.default_role @@ -121,13 +125,13 @@ class ContestCommandsCog(commands.Cog): period.advance_state() await channel.set_permissions(target_role, overwrite=overwrite) - await ctx.send(response) + await ctx.send(embed=helpers.success_embed(message=response)) @advance.error async def advance_error(self, error: errors.CommandError, ctx: Context) -> None: if isinstance(error, errors.MissingPermissions): - await ctx.send( - 'Check that the bot can actually modify roles, add reactions, see messages and send messages within this channel.') + await ctx.send(embed=helpers.error_embed( + message='Check that the bot can actually modify roles, add reactions, see messages and send messages within this channel.')) # noinspection PyDunderSlots, PyUnresolvedReferences @commands.command() @@ -155,7 +159,7 @@ class ContestCommandsCog(commands.Cog): with self.bot.get_session() as session: guild: Guild = session.query(Guild).get(ctx.guild.id) period: Period = guild.current_period - embed = discord.Embed(color=discord.Color(0x4a90e2), title='Status') + embed = discord.Embed(color=constants.GENERAL_COLOR, title='Status') value = f'<#{guild.submission_channel}>' if guild.submission_channel else 'Please set a submission channel.' embed.add_field(name='Submission Channel', value=value) @@ -197,8 +201,11 @@ class ContestCommandsCog(commands.Cog): description += f'`{str(i).zfill(2)}` {emote}<@{submission.user}> [Jump]({message.jump_url})\n' + if not description: + description = 'No one has submitted anything yet.' + embed = discord.Embed(title='Leaderboard', - colour=discord.Colour(0x4a90e2), + color=constants.GENERAL_COLOR, description=description, timestamp=datetime.datetime.utcnow()) embed.set_footer(text='Contest is still in progress...' if guild.current_period.active else 'Contest has finished.') diff --git a/bot/cogs/contest_events.py b/bot/cogs/contest_events.py index 730bfc0..cd764bd 100644 --- a/bot/cogs/contest_events.py +++ b/bot/cogs/contest_events.py @@ -1,5 +1,5 @@ import logging -from typing import List, Tuple +from typing import List import discord from discord.ext import commands @@ -21,6 +21,7 @@ logger.setLevel(constants.LOGGING_LEVEL) class ContestEventsCog(commands.Cog): """Manages all non-command events related to contests.""" + def __init__(self, bot: ContestBot): self.bot = bot @@ -37,18 +38,18 @@ class ContestEventsCog(commands.Cog): # Ensure that the submission contains at least one attachment if len(attachments) == 0: - await self.bot.reject(message, - f':no_entry_sign: {message.author.mention} Each submission must contain exactly one image.') + await self.bot.reject(message, f':no_entry_sign: {message.author.mention} ' + f'Each submission must contain exactly one image.') # Ensure the image contains no more than one attachment elif len(attachments) > 1: - await self.bot.reject(message, - f':no_entry_sign: {message.author.mention} Each submission must contain exactly one image.') + await self.bot.reject(message, f':no_entry_sign: {message.author.mention} ' + f'Each submission must contain exactly one image.') elif guild.current_period is None: await self.bot.reject(message, f':no_entry_sign: {message.author.mention} A period has not been started. ' f'Submissions should not be allowed at this moment.') elif guild.current_period != PeriodStates.SUBMISSIONS: - logger.warning( - f'Valid submission was sent outside of Submissions in {channel.id}/{message.id}. Permissions error? Removing.') + logger.warning(f'Valid submission was sent outside of Submissions in' + f' {channel.id}/{message.id}. Permissions error? Removing.') await message.delete() else: attachment = attachments[0] diff --git a/bot/constants.py b/bot/constants.py index f6bb3a6..34aa3de 100644 --- a/bot/constants.py +++ b/bot/constants.py @@ -1,14 +1,20 @@ import logging import os - # Path Constants from collections import namedtuple +import discord + BASE_DIR = os.path.dirname(os.path.abspath(os.path.join(__file__, '..'))) TOKEN = os.path.join(BASE_DIR, 'token.dat') DATABASE = os.path.join(BASE_DIR, 'database.db') DATABASE_URI = f'sqlite:///{DATABASE}' +# Discord-related constants +GENERAL_COLOR = discord.Color(0x4a90e2) +ERROR_COLOR = discord.Color(0xFF4848) +SUCCESS_COLOR = discord.Color(0x73E560) + # Other constants LOGGING_LEVEL = logging.DEBUG diff --git a/bot/helpers.py b/bot/helpers.py index b473a9b..484b73f 100644 --- a/bot/helpers.py +++ b/bot/helpers.py @@ -1,3 +1,4 @@ +import datetime from typing import Union import discord @@ -11,3 +12,20 @@ def is_upvote(emoji: Union[discord.Emoji, discord.PartialEmoji, str]) -> bool: if emoji.id == constants.Emoji.UPVOTE: return True return False + + +def general_embed(title: str = '', message: str = '', color: discord.Color = constants.GENERAL_COLOR, timestamp: bool = False) -> discord.Embed: + """A generic mostly unstyled embed with a blue color.""" + return discord.Embed(title=title, description=message, timestamp=datetime.datetime.utcnow() if timestamp else discord.Embed.Empty, color=color) + + +def error_embed(*args, **kwargs): + """A generic embed with a light red color.""" + kwargs['color'] = constants.ERROR_COLOR + return general_embed(*args, **kwargs) + + +def success_embed(*args, **kwargs): + """A generic embed with a light green color.""" + kwargs['color'] = constants.SUCCESS_COLOR + return general_embed(*args, **kwargs)