From 7a571e499a53268c8b03097adad7bf870da5c1ee Mon Sep 17 00:00:00 2001 From: Mega-JC <65417594+Mega-JC@users.noreply.github.com> Date: Thu, 27 Jun 2024 03:58:45 +0200 Subject: [PATCH] Refactor code in 'showcas_pre' extension --- pcbot/exts/showcase_pre.py | 143 +++++++++++++------------------------ 1 file changed, 51 insertions(+), 92 deletions(-) diff --git a/pcbot/exts/showcase_pre.py b/pcbot/exts/showcase_pre.py index 456baee..5c165d0 100644 --- a/pcbot/exts/showcase_pre.py +++ b/pcbot/exts/showcase_pre.py @@ -27,11 +27,9 @@ def __init__( self.entry_post_deletion_dict: dict[int, tuple[asyncio.Task[None], int]] = {} @staticmethod - async def delete_bad_entry_and_warning( - entry_msg: discord.Message, warn_msg: discord.Message, delay: float = 0.0 - ): - """A function to pardon a bad entry post with a grace period. If this coroutine is not cancelled during the - grace period specified in `delay` in seconds, it will delete both `entry_msg` and `warn_msg`, if possible. + async def delete_bad_thread(thread: discord.Thread, delay: float = 0.0): + """A function to pardon a bad thread with a grace period. If this coroutine is not cancelled during the + grace period specified in `delay` in seconds, it will delete `thread`, if possible. """ try: await asyncio.sleep(delay) # allow cancelling during delay @@ -39,18 +37,17 @@ async def delete_bad_entry_and_warning( return else: - for msg in (entry_msg, warn_msg): - # don't error here if messages were already deleted - try: - await msg.delete() - except discord.NotFound: - pass + try: + await thread.delete() + except discord.NotFound: + # don't error here if post was already deleted + pass @staticmethod - def entry_message_validity_check( + def starter_message_validity_check( message: discord.Message, min_chars=32, max_chars=float("inf") ): - """Checks if a post's starter message posted in a showcase channel has the right format. + """Checks if a thread's starter message has the right format. Returns ------- @@ -87,76 +84,22 @@ async def on_thread_create(self, thread: discord.Thread): else: await message.pin() - if not self.entry_message_validity_check(message): + if not self.starter_message_validity_check(message): deletion_datetime = datetime.datetime.now( datetime.timezone.utc - ) + datetime.timedelta(minutes=2) + ) + datetime.timedelta(minutes=5) warn_msg = await message.reply( "Your post must contain an attachment or text and safe links to be valid.\n\n" - "- Attachment-only entries must be replies to a previous entry of yours.\n" - "- Text-only entries must contain at least 32 characters (including links, but not links alone).\n\n" + "- Attachment-only entries must be in reference to a previous post of yours.\n" + "- Text-only posts must contain at least 32 characters (including links, but not links alone).\n\n" " If no changes are made, your post will be" f" deleted {snakecore.utils.create_markdown_timestamp(deletion_datetime, 'R')}." ) self.entry_post_deletion_dict[thread.id] = ( - asyncio.create_task( - self.delete_bad_entry_and_warning(message, warn_msg, delay=120) - ), + asyncio.create_task(self.delete_bad_thread(thread, delay=300)), warn_msg.id, ) - async def on_thread_delete(self, thread: discord.Thread): - if thread.parent_id != self.showcase_channel_id: - return - - if not any(tag.name.lower() == "invalid" for tag in thread.applied_tags): - alert_msg = await thread.send( - embed=discord.Embed.from_dict( - dict( - title="Post scheduled for deletion", - description=( - "This post is scheduled for deletion after the OP " - "deleted their starter message.\n\nIt will be deleted " - f"****." # 5 min. delay - ), - color=0x551111, - footer=dict(text="React with ❌ to cancel the deletion."), - ) - ) - ) - await alert_msg.add_reaction("❌") - - try: - await self.bot.wait_for( - "raw_reaction_add", - check=lambda event: event.message_id == alert_msg.id - and ( - event.user_id == thread.owner_id - or ( - event.member - and not event.member.bot - and ( - ( - perms := thread.permissions_for(event.member) - ).administrator - or perms.manage_messages - ) - ) - ) - and snakecore.utils.is_emoji_equal(event.emoji, "❌"), - timeout=300, - ) - except asyncio.TimeoutError: - try: - await thread.delete() - except discord.NotFound: - pass - else: - try: - await alert_msg.delete() - except discord.NotFound: - pass - @commands.Cog.listener() async def on_message_edit(self, old: discord.Message, new: discord.Message): if not ( @@ -167,7 +110,7 @@ async def on_message_edit(self, old: discord.Message, new: discord.Message): thread = new.channel - if not self.entry_message_validity_check(new): + if not self.starter_message_validity_check(new): if thread.id in self.entry_post_deletion_dict: deletion_data_tuple = self.entry_post_deletion_dict[thread.id] deletion_task = deletion_data_tuple[0] @@ -179,21 +122,23 @@ async def on_message_edit(self, old: discord.Message, new: discord.Message): warn_msg = await thread.fetch_message(deletion_data_tuple[1]) deletion_datetime = datetime.datetime.now( datetime.timezone.utc - ) + datetime.timedelta(minutes=2) + ) + datetime.timedelta(minutes=5) await warn_msg.edit( content=( - "I noticed your edit, but: Your post must contain an attachment or a (Discord recognized) link to be valid." - " If it doesn't contain any characters but an attachment, it must be a reply to another entry you created." - f" If no attachments are present, it must contain at least 32 characters (including any links, but not links alone)." + "I noticed your edit. However:\n\n" + "Your post must contain an attachment or text and safe " + "links to be valid.\n\n" + "- Attachment-only entries must be in reference to a " + "previous post of yours.\n" + "- Text-only posts must contain at least 32 " + "characters (including links, but not links alone).\n\n" " If no changes are made, your post will be" f" deleted {snakecore.utils.create_markdown_timestamp(deletion_datetime, 'R')}." ) ) self.entry_post_deletion_dict[thread.id] = ( asyncio.create_task( - self.delete_bad_entry_and_warning( - new, warn_msg, delay=120 - ) + self.delete_bad_thread(thread, delay=300) ), warn_msg.id, ) @@ -206,25 +151,23 @@ async def on_message_edit(self, old: discord.Message, new: discord.Message): else: # an edit led to an invalid post from a valid one deletion_datetime = datetime.datetime.now( datetime.timezone.utc - ) + datetime.timedelta(minutes=2) + ) + datetime.timedelta(minutes=5) warn_msg = await new.reply( - "Your post must contain an attachment or text and a (Discord recognized) link to be valid." - " If it doesn't contain any characters but an attachment, it must be a reply to another entry you created." - f" If no attachments are present, it must contain at least 32 characters (including any links, but not links alone)." + "Your post must contain an attachment or text and safe links to be valid.\n\n" + "- Attachment-only entries must be in reference to a previous post of yours.\n" + "- Text-only posts must contain at least 32 characters (including links, but not links alone).\n\n" " If no changes are made, your post will be" f" deleted {snakecore.utils.create_markdown_timestamp(deletion_datetime, 'R')}." ) self.entry_post_deletion_dict[thread.id] = ( - asyncio.create_task( - self.delete_bad_entry_and_warning(new, warn_msg, delay=120) - ), + asyncio.create_task(self.delete_bad_thread(thread, delay=300)), warn_msg.id, ) return elif ( - self.entry_message_validity_check(new) + self.starter_message_validity_check(new) and thread.id in self.entry_post_deletion_dict ): # an invalid entry was corrected deletion_data_tuple = self.entry_post_deletion_dict[thread.id] @@ -232,11 +175,12 @@ async def on_message_edit(self, old: discord.Message, new: discord.Message): if not deletion_task.done(): # too late to do anything try: deletion_task.cancel() # try to cancel deletion after noticing valid edit by sender - warn_msg = await thread.fetch_message(deletion_data_tuple[1]) - await warn_msg.delete() + await discord.PartialMessage( + channel=thread, id=deletion_data_tuple[1] + ).delete() except ( discord.NotFound - ): # cancelling didn't work, warning and post were already deleted + ): # cancelling didn't work, warning was already deleted pass if thread.id in self.entry_post_deletion_dict: @@ -244,10 +188,10 @@ async def on_message_edit(self, old: discord.Message, new: discord.Message): @commands.Cog.listener() async def on_message_delete(self, message: discord.Message): - if not ( isinstance(message.channel, discord.Thread) and message.channel.parent_id == self.showcase_channel_id + and message.channel.id == message.id # is starter message ): return @@ -271,6 +215,21 @@ async def on_message_delete(self, message: discord.Message): if thread.id in self.entry_post_deletion_dict: del self.entry_post_deletion_dict[thread.id] + @commands.Cog.listener() + async def on_raw_thread_delete(self, payload: discord.RawThreadDeleteEvent): + if ( + payload.parent_id != self.showcase_channel_id + or payload.thread_id not in self.entry_post_deletion_dict + ): + return + + deletion_data_tuple = self.entry_post_deletion_dict[payload.thread_id] + deletion_task = deletion_data_tuple[0] + if not deletion_task.done(): + deletion_task.cancel() + + del self.entry_post_deletion_dict[payload.thread_id] + @snakecore.commands.decorators.with_config_kwargs async def setup(