diff options
author | 2022-11-26 12:50:49 +0000 | |
---|---|---|
committer | 2022-11-26 12:50:49 +0000 | |
commit | 47ea9760bd628db3816ab6b830f9167f7092773b (patch) | |
tree | 6491c9b2291fee2b9fa26776d9cd65ec580c0558 | |
parent | Merge pull request #2335 from python-discord/help-system-timeout (diff) | |
parent | Refactor Thread Error Catching (diff) |
Merge pull request #2337 from python-discord/help-forum-fixes
Misc Fixes For Help Forum
-rw-r--r-- | bot/exts/help_channels/_channel.py | 31 | ||||
-rw-r--r-- | bot/exts/help_channels/_cog.py | 3 | ||||
-rw-r--r-- | bot/pagination.py | 100 | ||||
-rw-r--r-- | bot/utils/messages.py | 6 |
4 files changed, 76 insertions, 64 deletions
diff --git a/bot/exts/help_channels/_channel.py b/bot/exts/help_channels/_channel.py index cc3d831b0..5fc39b623 100644 --- a/bot/exts/help_channels/_channel.py +++ b/bot/exts/help_channels/_channel.py @@ -1,5 +1,5 @@ """Contains all logic to handle changes to posts in the help forum.""" - +import asyncio import textwrap import discord @@ -52,6 +52,15 @@ async def _close_help_thread(closed_thread: discord.Thread, closed_on: _stats.Cl poster = closed_thread.owner cooldown_role = closed_thread.guild.get_role(constants.Roles.help_cooldown) + + if poster is None: + # We can't include the owner ID/name here since the thread only contains None + log.info( + f"Failed to remove cooldown role for owner of thread ({closed_thread.id}). " + f"The user is likely no longer on the server." + ) + return + await members.handle_role_change(poster, poster.remove_roles, cooldown_role) @@ -80,10 +89,14 @@ async def send_opened_post_dm(thread: discord.Thread) -> None: try: message = await thread.fetch_message(thread.id) except discord.HTTPException: - log.warning(f"Could not fetch message for thread {thread.name} ({thread.id})") + log.warning(f"Could not fetch message for thread {thread.id}") return - formatted_message = textwrap.shorten(message.content, width=100, placeholder="...") + formatted_message = textwrap.shorten(message.content, width=100, placeholder="...").strip() + if formatted_message is None: + # This most likely means the initial message is only an image or similar + formatted_message = "No text content." + embed.add_field(name="Your message", value=formatted_message, inline=False) embed.add_field( name="Conversation", @@ -109,11 +122,19 @@ async def help_thread_opened(opened_thread: discord.Thread, *, reopen: bool = Fa await _close_help_thread(opened_thread, _stats.ClosingReason.CLEANUP) return + # Discord sends the open event long before the thread is ready for actions in the API. + # This causes actions such as fetching the message, pinning message, etc to fail. + # We sleep here to try and delay our code enough so the thread is ready in the API. + await asyncio.sleep(2) + await send_opened_post_dm(opened_thread) - if opened_thread.starter_message: - # To cover the case where the user deletes their starter message before code execution reaches this line. + try: await opened_thread.starter_message.pin() + except discord.HTTPException as e: + # Suppress if the message was not found, most likely deleted + if e.code != 10008: + raise e await send_opened_post_message(opened_thread) diff --git a/bot/exts/help_channels/_cog.py b/bot/exts/help_channels/_cog.py index 50f8416fc..bb2f43c5a 100644 --- a/bot/exts/help_channels/_cog.py +++ b/bot/exts/help_channels/_cog.py @@ -119,9 +119,8 @@ class HelpForum(commands.Cog): if thread.parent_id != self.help_forum_channel_id: return - await _channel.help_thread_opened(thread) - await self.post_with_disallowed_title_check(thread) + await _channel.help_thread_opened(thread) @commands.Cog.listener() async def on_thread_update(self, before: discord.Thread, after: discord.Thread) -> None: diff --git a/bot/pagination.py b/bot/pagination.py index 10bef1c9f..0ef5808cc 100644 --- a/bot/pagination.py +++ b/bot/pagination.py @@ -301,71 +301,57 @@ class LinePaginator(Paginator): if str(reaction.emoji) == DELETE_EMOJI: log.debug("Got delete reaction") return await message.delete() - - if reaction.emoji == FIRST_EMOJI: - await message.remove_reaction(reaction.emoji, user) - current_page = 0 - - log.debug(f"Got first page reaction - changing to page 1/{len(paginator.pages)}") + elif reaction.emoji in PAGINATION_EMOJI: + total_pages = len(paginator.pages) + try: + await message.remove_reaction(reaction.emoji, user) + except discord.HTTPException as e: + # Suppress if trying to act on an archived thread. + if e.code != 50083: + raise e + + if reaction.emoji == FIRST_EMOJI: + current_page = 0 + log.debug(f"Got first page reaction - changing to page 1/{total_pages}") + elif reaction.emoji == LAST_EMOJI: + current_page = len(paginator.pages) - 1 + log.debug(f"Got last page reaction - changing to page {current_page + 1}/{total_pages}") + elif reaction.emoji == LEFT_EMOJI: + if current_page <= 0: + log.debug("Got previous page reaction, but we're on the first page - ignoring") + continue + + current_page -= 1 + log.debug(f"Got previous page reaction - changing to page {current_page + 1}/{total_pages}") + elif reaction.emoji == RIGHT_EMOJI: + if current_page >= len(paginator.pages) - 1: + log.debug("Got next page reaction, but we're on the last page - ignoring") + continue + + current_page += 1 + log.debug(f"Got next page reaction - changing to page {current_page + 1}/{total_pages}") embed.description = paginator.pages[current_page] - if footer_text: - embed.set_footer(text=f"{footer_text} (Page {current_page + 1}/{len(paginator.pages)})") - else: - embed.set_footer(text=f"Page {current_page + 1}/{len(paginator.pages)}") - await message.edit(embed=embed) - - if reaction.emoji == LAST_EMOJI: - await message.remove_reaction(reaction.emoji, user) - current_page = len(paginator.pages) - 1 - - log.debug(f"Got last page reaction - changing to page {current_page + 1}/{len(paginator.pages)}") - embed.description = paginator.pages[current_page] if footer_text: embed.set_footer(text=f"{footer_text} (Page {current_page + 1}/{len(paginator.pages)})") else: embed.set_footer(text=f"Page {current_page + 1}/{len(paginator.pages)}") - await message.edit(embed=embed) - - if reaction.emoji == LEFT_EMOJI: - await message.remove_reaction(reaction.emoji, user) - - if current_page <= 0: - log.debug("Got previous page reaction, but we're on the first page - ignoring") - continue - - current_page -= 1 - log.debug(f"Got previous page reaction - changing to page {current_page + 1}/{len(paginator.pages)}") - embed.description = paginator.pages[current_page] - - if footer_text: - embed.set_footer(text=f"{footer_text} (Page {current_page + 1}/{len(paginator.pages)})") - else: - embed.set_footer(text=f"Page {current_page + 1}/{len(paginator.pages)}") - - await message.edit(embed=embed) - - if reaction.emoji == RIGHT_EMOJI: - await message.remove_reaction(reaction.emoji, user) - - if current_page >= len(paginator.pages) - 1: - log.debug("Got next page reaction, but we're on the last page - ignoring") - continue - - current_page += 1 - log.debug(f"Got next page reaction - changing to page {current_page + 1}/{len(paginator.pages)}") - - embed.description = paginator.pages[current_page] - - if footer_text: - embed.set_footer(text=f"{footer_text} (Page {current_page + 1}/{len(paginator.pages)})") - else: - embed.set_footer(text=f"Page {current_page + 1}/{len(paginator.pages)}") - - await message.edit(embed=embed) + try: + await message.edit(embed=embed) + except discord.HTTPException as e: + if e.code == 50083: + # Trying to act on an archived thread, just ignore and abort + break + else: + raise e log.debug("Ending pagination and clearing reactions.") with suppress(discord.NotFound): - await message.clear_reactions() + try: + await message.clear_reactions() + except discord.HTTPException as e: + # Suppress if trying to act on an archived thread. + if e.code != 50083: + raise e diff --git a/bot/utils/messages.py b/bot/utils/messages.py index a5ed84351..8a968f659 100644 --- a/bot/utils/messages.py +++ b/bot/utils/messages.py @@ -101,9 +101,15 @@ async def wait_for_deletion( await message.clear_reactions() else: await message.delete() + except discord.NotFound: log.trace(f"wait_for_deletion: message {message.id} deleted prematurely.") + except discord.HTTPException: + if not isinstance(message.channel, discord.Thread): + # Threads might not be accessible by the time the timeout expires + raise + async def send_attachments( message: discord.Message, |