aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar ChrisJL <[email protected]>2022-11-26 12:50:49 +0000
committerGravatar GitHub <[email protected]>2022-11-26 12:50:49 +0000
commit47ea9760bd628db3816ab6b830f9167f7092773b (patch)
tree6491c9b2291fee2b9fa26776d9cd65ec580c0558
parentMerge pull request #2335 from python-discord/help-system-timeout (diff)
parentRefactor 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.py31
-rw-r--r--bot/exts/help_channels/_cog.py3
-rw-r--r--bot/pagination.py100
-rw-r--r--bot/utils/messages.py6
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,