EveCogs/wormhole/ui/modals.py
Rosie Val 5e41658d7d Re-enable Report/Delete/Profile context menus, remove Bookmark, fix reports
Re-enabled the "Report to Wormhole", "Delete from Network", and "Wormhole
Profile" context menus (previously disabled entirely). Removed "Bookmark
(Wormhole)" per request — the prefix `wh bm list`/`clear` commands are
untouched, but note this was the only way to *add* a bookmark, so that
feature is now list/clear-only for existing entries.

Wormhole Profile is now considerably richer: account creation date, total
cross-network message count, global-ban status, and per-network karma/
server-count/muted/banned status, sorted busiest-network-first.

Fixed both report-creation paths (the "Report to Wormhole" context menu's
modal, and `wh report msg`): report_counter was read before the config lock
and written after, so concurrent reports could collide on the same id with
the counter never advancing. Now computed and saved atomically inside the
lock. Also gave both paths full parity — message id, jump link, and a real
content preview (the context-menu path previously stored `hash()` of the
content, which is randomized per-process in Python 3 and useless for
anything; the prefix-command path never even recorded who wrote the
message). `wh report view` now surfaces all of it.

Also added the "Find Origin" context menu (right-click a message -> find
its true source server/channel/author across the network) as a separate,
complementary feature to Profile — not a replacement.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-29 00:02:49 +01:00

78 lines
2.9 KiB
Python

"""Discord UI modals for Wormhole (e.g. report form)."""
from __future__ import annotations
from datetime import datetime, timezone
from typing import TYPE_CHECKING
import discord
from ..utils import ok_embed, truncate, warn_embed
if TYPE_CHECKING:
from ..core import Wormhole
class ReportModal(discord.ui.Modal, title="Report Message"):
reason = discord.ui.TextInput(
label="Reason",
style=discord.TextStyle.paragraph,
placeholder="Describe why you're reporting this message...",
required=True,
max_length=1000,
)
def __init__(self, cog: Wormhole, net_name: str, message: discord.Message) -> None:
super().__init__()
self.cog = cog
self.net_name = net_name
self.message = message
async def on_submit(self, interaction: discord.Interaction) -> None:
# report_id must be computed and written inside the same locked
# section — reading report_counter beforehand let two concurrent
# reports land on the same id and left the counter not advanced.
async with self.cog.config.networks() as ns:
nd = ns.get(self.net_name)
if not nd:
await interaction.response.send_message("Network not found.", ephemeral=True)
return
report_id = nd.get("report_counter", 0) + 1
report = {
"id": report_id,
"reporter_id": interaction.user.id,
"author_id": self.message.author.id,
"message_id": self.message.id,
"channel_id": self.message.channel.id,
"guild_id": self.message.guild.id if self.message.guild else None,
"content_preview": truncate(self.message.content or "*[no text]*", 300),
"jump_url": self.message.jump_url,
"reason": self.reason.value,
"timestamp": datetime.now(timezone.utc).isoformat(),
"resolved": False,
"resolved_by": None,
"resolution": None,
}
nd.setdefault("reports", []).append(report)
nd["report_counter"] = report_id
owner = self.cog.bot.get_user(nd.get("owner_id"))
if owner:
try:
await owner.send(
embed=warn_embed(
f"**Report #{report_id}** in `{self.net_name}`\n"
f"Reporter: {interaction.user} (`{interaction.user.id}`)\n"
f"Author: {self.message.author} (`{self.message.author.id}`)\n"
f"Reason: {self.reason.value}",
title="🚩 New Report",
)
)
except discord.Forbidden:
pass
await interaction.response.send_message(
embed=ok_embed(f"Report #{report_id} submitted. Staff will review it."),
ephemeral=True,
)