Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion core/clients.py
Original file line number Diff line number Diff line change
Expand Up @@ -661,9 +661,18 @@ async def append_log(
channel_id: str = "",
type_: str = "thread_message",
) -> dict:
from core.utils import extract_forwarded_content

channel_id = str(channel_id) or str(message.channel.id)
message_id = str(message_id) or str(message.id)

content = message.content or ""
if forwarded := extract_forwarded_content(message):
if content:
content += "\n" + forwarded
else:
content = forwarded

data = {
"timestamp": str(message.created_at),
"message_id": message_id,
Expand All @@ -674,7 +683,7 @@ async def append_log(
"avatar_url": message.author.display_avatar.url if message.author.display_avatar else None,
"mod": not isinstance(message.channel, DMChannel),
},
"content": message.content,
"content": content,
"type": type_,
"attachments": [
{
Expand Down
11 changes: 10 additions & 1 deletion core/thread.py
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,10 @@ async def snooze(self, moderator=None, command_used=None, snooze_for=None):
"messages": [
{
"author_id": m.author.id,
"content": m.content,
"content": (
(m.content or "")
+ (("\n" + extract_forwarded_content(m)) if extract_forwarded_content(m) else "")
).strip(),
"attachments": [a.url for a in m.attachments],
"embeds": [e.to_dict() for e in m.embeds],
"created_at": m.created_at.isoformat(),
Expand Down Expand Up @@ -259,6 +262,9 @@ async def snooze(self, moderator=None, command_used=None, snooze_for=None):

logging.info(f"[SNOOZE] DB update result: {result.modified_count}")

# Dispatch thread_snoozed event for plugins
self.bot.dispatch("thread_snoozed", self, moderator, snooze_for)

behavior = behavior_pre
if behavior == "move":
# Move the channel to the snoozed category (if configured) and optionally apply a prefix
Expand Down Expand Up @@ -751,6 +757,9 @@ async def _ensure_genesis(force: bool = False):
# Mark unsnooze as complete
self._unsnoozing = False

# Dispatch thread_unsnoozed event for plugins
self.bot.dispatch("thread_unsnoozed", self)

# Process queued commands
await self._process_command_queue()

Expand Down
76 changes: 43 additions & 33 deletions core/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -658,39 +658,49 @@ def extract_forwarded_content(message) -> typing.Optional[str]:

try:
# Handle multi-forward (message_snapshots)
if hasattr(message, "flags") and getattr(message.flags, "has_snapshot", False):
if hasattr(message, "message_snapshots") and message.message_snapshots:
forwarded_parts = []
for snap in message.message_snapshots:
author = getattr(snap, "author", None)
author_name = getattr(author, "name", "Unknown") if author else "Unknown"
snap_content = getattr(snap, "content", "")

if snap_content:
# Truncate very long messages to prevent spam
if len(snap_content) > 500:
snap_content = snap_content[:497] + "..."
forwarded_parts.append(f"**{author_name}:** {snap_content}")
elif getattr(snap, "embeds", None):
for embed in snap.embeds:
if hasattr(embed, "description") and embed.description:
embed_desc = embed.description
if len(embed_desc) > 300:
embed_desc = embed_desc[:297] + "..."
forwarded_parts.append(f"**{author_name}:** {embed_desc}")
break
elif getattr(snap, "attachments", None):
attachment_info = ", ".join(
[getattr(a, "filename", "Unknown") for a in snap.attachments[:3]]
)
if len(snap.attachments) > 3:
attachment_info += f" (+{len(snap.attachments) - 3} more)"
forwarded_parts.append(f"**{author_name}:** [Attachments: {attachment_info}]")
else:
forwarded_parts.append(f"**{author_name}:** [No content]")

if forwarded_parts:
return "\n".join(forwarded_parts)
# Check directly for snapshots as flags.has_snapshot can be unreliable in some versions
if getattr(message, "message_snapshots", None):
forwarded_parts = []
for snap in message.message_snapshots:
author = getattr(snap, "author", None)
# If author is missing, we can try to rely on the container message context or just omit.
# Since we can't reliably get the original author from snapshot in this state, we focus on content.

snap_content = getattr(snap, "content", "")

formatted_part = "📨 **Forwarded Message**\n"

if snap_content:
if len(snap_content) > 500:
snap_content = snap_content[:497] + "..."
formatted_part += "\n".join([f"{line}" for line in snap_content.splitlines()]) + "\n"

if getattr(snap, "embeds", None):
for embed in snap.embeds:
if hasattr(embed, "description") and embed.description:
embed_desc = embed.description
if len(embed_desc) > 300:
embed_desc = embed_desc[:297] + "..."
formatted_part += (
"\n".join([f"> {line}" for line in embed_desc.splitlines()]) + "\n"
)
break # One embed preview is usually enough

if getattr(snap, "attachments", None):
attachment_info = ", ".join(
[getattr(a, "filename", "Unknown") for a in snap.attachments[:3]]
)
if len(snap.attachments) > 3:
attachment_info += f" (+{len(snap.attachments) - 3} more)"
formatted_part += f"[Attachments: {attachment_info}]\n"

# Add source link to the container message since snapshot doesn't have its own public link
formatted_part += f"\n**Source:** {message.jump_url}"
Comment on lines +697 to +698
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This always returns a link to the forwarded message instance that is in the DM with the bot, rather than to the original message that was forwarded - which won't be accessible to the moderator reviewing the content in the logviewer.

The "Context" line when a forwarded message is sent in a Modmail ticket channel (which appears when the forwarded message location is one that the bot is able to fetch) would be a better solution here - perhaps something like what is done in thread.py

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That would be a nice solution yea. If you are able to PR this that would be great, otherwise i will look into this either this week or next week.


forwarded_parts.append(formatted_part)

if forwarded_parts:
return "\n".join(forwarded_parts)

# Handle single-message forward
elif getattr(message, "type", None) == getattr(discord.MessageType, "forward", None):
Expand Down
Loading