diff options
| author | 2021-07-25 00:39:22 +0300 | |
|---|---|---|
| committer | 2021-07-25 00:39:22 +0300 | |
| commit | 19cd66fa1615ed8f220cef8dbff5f826c7d4670c (patch) | |
| tree | 05e96b70494387cbe99004c29c2a8a6ddfa4b4d3 | |
| parent | Fix end command docstring (diff) | |
Improved codejam end confirmation
The command now sends the details of all channels about to be deleted to the pasting service, and confirmation is done through a reaction by the invoker of the command within a limited time (10 seconds).
| -rw-r--r-- | bot/exts/events/code_jams/_cog.py | 74 |
1 files changed, 59 insertions, 15 deletions
diff --git a/bot/exts/events/code_jams/_cog.py b/bot/exts/events/code_jams/_cog.py index 83e2e18ce..d0c206b5e 100644 --- a/bot/exts/events/code_jams/_cog.py +++ b/bot/exts/events/code_jams/_cog.py @@ -1,3 +1,4 @@ +import asyncio import csv import logging import typing as t @@ -10,10 +11,12 @@ from discord.ext import commands from bot.bot import Bot from bot.constants import Emojis, Roles from bot.exts.events.code_jams import _channels +from bot.utils.services import send_to_paste_service log = logging.getLogger(__name__) TEAM_LEADERS_COLOUR = 0x11806a +DELETION_REACTION = "\U0001f4a5" class CodeJams(commands.Cog): @@ -22,8 +25,6 @@ class CodeJams(commands.Cog): def __init__(self, bot: Bot): self.bot = bot - self.end_counter = 0 - @commands.group(aliases=("cj", "jam")) @commands.has_any_role(Roles.admins) async def codejam(self, ctx: commands.Context) -> None: @@ -80,24 +81,67 @@ class CodeJams(commands.Cog): """ Deletes all code jam channels. - Call it three times while spinning around for it all to end. + Displays a confirmation message with the categories and channels to be deleted. Pressing the added reaction + deletes those channels. """ - self.end_counter += 1 - if self.end_counter == 1: - await ctx.send("Are you sure about that?") - return - if self.end_counter == 2: - await ctx.send("Are you *really really* sure about that?") + def predicate_deletion_emoji_reaction(reaction: discord.Reaction, user: discord.User) -> bool: + """Return True if the reaction :boom: was added by the context message author on this message.""" + return ( + reaction.message.id == message.id + and user.id == ctx.author.id + and str(reaction) == DELETION_REACTION + ) + + # A copy of the list of channels is stored. This is to make sure that we delete precisely the channels displayed + # in the confirmation message. + categories = self.jam_categories(ctx.guild) + category_channels = {category: category.channels.copy() for category in categories} + + confirmation_message = await self._build_confirmation_message(category_channels) + message = await ctx.send(confirmation_message) + await message.add_reaction(DELETION_REACTION) + try: + await self.bot.wait_for( + 'reaction_add', + check=predicate_deletion_emoji_reaction, + timeout=10 + ) + + except asyncio.TimeoutError: + await message.clear_reaction(DELETION_REACTION) return - self.end_counter = 0 + else: + await message.clear_reaction(DELETION_REACTION) + for category, channels in category_channels.items(): + for channel in channels: + await channel.delete(reason="Code jam ended.") + await category.delete(reason="Code jam ended.") - for category in self.jam_categories(ctx.guild): - for channel in category.channels: - await channel.delete(reason="Code jam ended.") - await category.delete(reason="Code jam ended.") + await message.add_reaction(Emojis.check_mark) + + @staticmethod + async def _build_confirmation_message( + categories: dict[discord.CategoryChannel, list[discord.abc.GuildChannel]] + ) -> str: + """Sends details of the channels to be deleted to the pasting service, and formats the confirmation message.""" + def channel_repr(channel: discord.abc.GuildChannel) -> str: + """Formats the channel name and ID and a readable format.""" + return f"{channel.name} ({channel.id})" + + def format_category_info(category: discord.CategoryChannel, channels: list[discord.abc.GuildChannel]) -> str: + """Displays the category and the channels within it in a readable format.""" + return f"{channel_repr(category)}:" + "".join(f"\n - {channel_repr(channel)}" for channel in channels) + + deletion_details = "\n\n".join( + format_category_info(category, channels) for category, channels in categories.items() + ) + + url = await send_to_paste_service(deletion_details) + if url is None: + url = "**Unable to send deletion details to the pasting service.**" - await ctx.message.add_reaction(Emojis.check_mark) + return f"Are you sure you want to delete all code jam channels?\n\nThe channels to be deleted: {url}" @codejam.command() @commands.has_any_role(Roles.admins, Roles.code_jam_event_team) |