-
-
Notifications
You must be signed in to change notification settings - Fork 4.7k
fix: plain replies deletion and edits #3416
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 3 commits
f33b06c
20af225
e620a03
4e38eaa
420ece0
2992eb0
2758afe
9e549a4
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -1724,11 +1724,11 @@ async def edit(self, ctx, message_id: Optional[int] = None, *, message: str): | |||||||||||
|
|
||||||||||||
| try: | ||||||||||||
| await thread.edit_message(message_id, message) | ||||||||||||
| except ValueError: | ||||||||||||
| except ValueError as e: | ||||||||||||
| return await ctx.send( | ||||||||||||
| embed=discord.Embed( | ||||||||||||
| title="Failed", | ||||||||||||
| description="Cannot find a message to edit. Plain messages are not supported.", | ||||||||||||
| description=str(e), | ||||||||||||
| color=self.bot.error_color, | ||||||||||||
| ) | ||||||||||||
| ) | ||||||||||||
|
|
@@ -2274,7 +2274,7 @@ async def delete(self, ctx, message_id: int = None): | |||||||||||
| return await ctx.send( | ||||||||||||
| embed=discord.Embed( | ||||||||||||
| title="Failed", | ||||||||||||
| description="Cannot find a message to delete. Plain messages are not supported.", | ||||||||||||
| description=str(e), | ||||||||||||
|
||||||||||||
| description=str(e), | |
| description=( | |
| "I couldn't delete that message. It may not exist, may not have been " | |
| "sent via Modmail, or cannot be deleted." | |
| ), |
| Original file line number | Diff line number | Diff line change | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -1345,11 +1345,17 @@ async def find_linked_messages( | |||||||||||||
| or not message1.embeds[0].author.url | ||||||||||||||
| or message1.author != self.bot.user | ||||||||||||||
| ): | ||||||||||||||
| logger.debug( | ||||||||||||||
| f"Malformed thread message for deletion: embeds={bool(message1.embeds)}, author_url={getattr(message1.embeds[0], 'author', None) and message1.embeds[0].author.url}, author={message1.author}" | ||||||||||||||
| ) | ||||||||||||||
| # Keep original error string to avoid extra failure embeds in on_message_delete | ||||||||||||||
| raise ValueError("Malformed thread message.") | ||||||||||||||
| is_plain = False | ||||||||||||||
| if message1.embeds and message1.embeds[0].footer and message1.embeds[0].footer.text: | ||||||||||||||
| if message1.embeds[0].footer.text.startswith("[PLAIN]"): | ||||||||||||||
| is_plain = True | ||||||||||||||
|
|
||||||||||||||
| if not is_plain: | ||||||||||||||
| logger.debug( | ||||||||||||||
| f"Malformed thread message for deletion: embeds={bool(message1.embeds)}, author_url={getattr(message1.embeds[0], 'author', None) and message1.embeds[0].author.url}, author={message1.author}" | ||||||||||||||
| ) | ||||||||||||||
| # Keep original error string to avoid extra failure embeds in on_message_delete | ||||||||||||||
| raise ValueError("Malformed thread message.") | ||||||||||||||
|
|
||||||||||||||
| elif message_id is not None: | ||||||||||||||
| try: | ||||||||||||||
|
|
@@ -1374,8 +1380,39 @@ async def find_linked_messages( | |||||||||||||
| return message1, None | ||||||||||||||
| # else: fall through to relay checks below | ||||||||||||||
|
|
||||||||||||||
| # Non-note path (regular relayed messages): require author.url and colors | ||||||||||||||
| if not ( | ||||||||||||||
| is_plain = False | ||||||||||||||
| if message1.embeds and message1.embeds[0].footer and message1.embeds[0].footer.text: | ||||||||||||||
| if message1.embeds[0].footer.text.startswith("[PLAIN]"): | ||||||||||||||
| is_plain = True | ||||||||||||||
|
|
||||||||||||||
| if is_plain: | ||||||||||||||
| creation_time = message1.created_at | ||||||||||||||
|
|
||||||||||||||
| mod_tag = message1.embeds[0].footer.text.replace("[PLAIN]", "", 1).strip() | ||||||||||||||
| author_name = message1.embeds[0].author.name | ||||||||||||||
| desc = message1.embeds[0].description or "" | ||||||||||||||
| prefix = f"**{mod_tag} " if mod_tag else "**" | ||||||||||||||
| plain_content_expected = f"{prefix}{author_name}:** {desc}" | ||||||||||||||
|
|
||||||||||||||
| messages = [message1] | ||||||||||||||
| for user in self.recipients: | ||||||||||||||
| async for msg in user.history(limit=50, around=creation_time): | ||||||||||||||
| if abs((msg.created_at - creation_time).total_seconds()) > 15: | ||||||||||||||
| continue | ||||||||||||||
| if msg.author != self.bot.user: | ||||||||||||||
| continue | ||||||||||||||
| if msg.embeds: | ||||||||||||||
| continue | ||||||||||||||
|
|
||||||||||||||
| if msg.content == plain_content_expected: | ||||||||||||||
| messages.append(msg) | ||||||||||||||
| break | ||||||||||||||
|
|
||||||||||||||
| if len(messages) > 1: | ||||||||||||||
| return messages | ||||||||||||||
| raise ValueError("Linked Plain DM message not found.") | ||||||||||||||
|
|
||||||||||||||
| if not is_plain and not ( | ||||||||||||||
| message1.embeds | ||||||||||||||
| and message1.embeds[0].author.url | ||||||||||||||
| and message1.embeds[0].color | ||||||||||||||
|
|
@@ -1387,61 +1424,38 @@ async def find_linked_messages( | |||||||||||||
| raise ValueError("Thread message not found.") | ||||||||||||||
|
|
||||||||||||||
| if message1.embeds[0].footer and "Internal Message" in message1.embeds[0].footer.text: | ||||||||||||||
| if not note: | ||||||||||||||
| logger.warning( | ||||||||||||||
| f"Message {message_id} is an internal message, but note deletion not requested." | ||||||||||||||
| ) | ||||||||||||||
| raise ValueError("Thread message is an internal message, not a note.") | ||||||||||||||
| logger.warning( | ||||||||||||||
| f"Message {message_id} is an internal message, but note deletion not requested." | ||||||||||||||
| ) | ||||||||||||||
| raise ValueError("Thread message is an internal message, not a note.") | ||||||||||||||
| # Internal bot-only message treated similarly; keep None sentinel | ||||||||||||||
| return message1, None | ||||||||||||||
|
|
||||||||||||||
| if message1.embeds[0].color.value != self.bot.mod_color and not ( | ||||||||||||||
| either_direction and message1.embeds[0].color.value == self.bot.recipient_color | ||||||||||||||
| ): | ||||||||||||||
| logger.warning("Message color does not match mod/recipient colors.") | ||||||||||||||
| raise ValueError("Thread message not found.") | ||||||||||||||
| else: | ||||||||||||||
| async for message1 in self.channel.history(): | ||||||||||||||
| if ( | ||||||||||||||
| message1.embeds | ||||||||||||||
| and message1.embeds[0].author.url | ||||||||||||||
| and message1.embeds[0].color | ||||||||||||||
| and ( | ||||||||||||||
| message1.embeds[0].color.value == self.bot.mod_color | ||||||||||||||
| or (either_direction and message1.embeds[0].color.value == self.bot.recipient_color) | ||||||||||||||
| ) | ||||||||||||||
| and message1.embeds[0].author.url.split("#")[-1].isdigit() | ||||||||||||||
| and message1.author == self.bot.user | ||||||||||||||
| ): | ||||||||||||||
| break | ||||||||||||||
| else: | ||||||||||||||
| raise ValueError("Thread message not found.") | ||||||||||||||
|
|
||||||||||||||
| try: | ||||||||||||||
| joint_id = int(message1.embeds[0].author.url.split("#")[-1]) | ||||||||||||||
| except ValueError: | ||||||||||||||
| raise ValueError("Malformed thread message.") | ||||||||||||||
|
|
||||||||||||||
| messages = [message1] | ||||||||||||||
| for user in self.recipients: | ||||||||||||||
| async for msg in user.history(): | ||||||||||||||
| if either_direction: | ||||||||||||||
| if msg.id == joint_id: | ||||||||||||||
| return message1, msg | ||||||||||||||
| try: | ||||||||||||||
| joint_id = int(message1.embeds[0].author.url.split("#")[-1]) | ||||||||||||||
| except ValueError: | ||||||||||||||
| raise ValueError("Malformed thread message.") | ||||||||||||||
|
|
||||||||||||||
| messages = [message1] | ||||||||||||||
| for user in self.recipients: | ||||||||||||||
| async for msg in user.history(): | ||||||||||||||
| if either_direction: | ||||||||||||||
| if msg.id == joint_id: | ||||||||||||||
| return message1, msg | ||||||||||||||
|
|
||||||||||||||
| if not (msg.embeds and msg.embeds[0].author.url): | ||||||||||||||
| continue | ||||||||||||||
| try: | ||||||||||||||
| if int(msg.embeds[0].author.url.split("#")[-1]) == joint_id: | ||||||||||||||
| messages.append(msg) | ||||||||||||||
| break | ||||||||||||||
| except ValueError: | ||||||||||||||
| continue | ||||||||||||||
| if not (msg.embeds and msg.embeds[0].author.url): | ||||||||||||||
|
||||||||||||||
| continue | ||||||||||||||
| try: | ||||||||||||||
| if int(msg.embeds[0].author.url.split("#")[-1]) == joint_id: | ||||||||||||||
| messages.append(msg) | ||||||||||||||
| break | ||||||||||||||
| except ValueError: | ||||||||||||||
| continue | ||||||||||||||
|
|
||||||||||||||
| if len(messages) > 1: | ||||||||||||||
| return messages | ||||||||||||||
| if len(messages) > 1: | ||||||||||||||
| return messages | ||||||||||||||
|
|
||||||||||||||
|
||||||||||||||
| if is_plain: | |
| # For plain messages, it's acceptable that no linked DM is found; | |
| # in that case, just return the original message. | |
| return messages |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Returning the raw exception message str(e) directly to users in error messages can expose internal implementation details or confusing technical messages. Consider mapping specific ValueError messages to more user-friendly error descriptions, or ensure that all ValueError messages raised in the thread module are written with end-users in mind.