refactor: Wormhole v4.0.0 — full modular architecture with hierarchical staff
BREAKING: Complete cog restructure from monolithic wormhole.py into modular architecture.
## Architecture
- models/permissions.py — Role IntEnum (MEMBER→OWNER), requires_role() decorator
- models/config.py — DEFAULT_NETWORK/DEFAULT_GLOBAL with 80+ config keys
- models/message_map.py — MessageMap class (extracted from _MessageMap)
- services/emoji.py — Foreign emoji resolution and relay
- ui/views.py — Reply jump button view
- ui/modals.py — Report modal
- core.py — Main Wormhole class, helpers, background loops, context menus
- commands/ — 13 command modules as mixin classes
- listeners/ — relay pipeline, edit/delete/reaction sync, typing/pin sync
## Staff System (new)
Per-network hierarchical roles replacing flat owner/staff:
Bot Owner (Red built-in) — global override
└─ Network Owner → Admin → Moderator → Helper → Member
Each role assigned per-network. Higher roles can assign lower.
Legacy staff_ids auto-migrated to ADMIN role.
## Enhanced Moderation
- Server-level ban/mute (not just user-level)
- Allowlist mode (only whitelisted servers can send)
- Mod edit and nuke (delete N messages by user)
- Anti-raid detector with auto-freeze
- Expanded automod: anti-zalgo, anti-emote-spam, anti-newline-spam
## Commands (100+)
network, settings, staff, moderation, filters, social, dm, mentions,
tos, reports, bridge, advanced (polls/afk/auto-responses/scheduled/
analytics/quiet-hours/colours/invites/announcements/blackout/portal),
debug (health/trace/testsend/relaydebug/backup/restore/version)
## Files
- 30 Python files, 5,274 lines total (was 4,782 in monolith)
- Original wormhole.py preserved for reference
- utils.py unchanged (all helpers reused)
2026-05-14 19:07:49 +00:00
|
|
|
"""Persistent and ephemeral views for Wormhole messages."""
|
|
|
|
|
|
|
|
|
|
from __future__ import annotations
|
|
|
|
|
|
|
|
|
|
import discord
|
2026-08-05 13:07:20 -04:00
|
|
|
from typing import Optional
|
refactor: Wormhole v4.0.0 — full modular architecture with hierarchical staff
BREAKING: Complete cog restructure from monolithic wormhole.py into modular architecture.
## Architecture
- models/permissions.py — Role IntEnum (MEMBER→OWNER), requires_role() decorator
- models/config.py — DEFAULT_NETWORK/DEFAULT_GLOBAL with 80+ config keys
- models/message_map.py — MessageMap class (extracted from _MessageMap)
- services/emoji.py — Foreign emoji resolution and relay
- ui/views.py — Reply jump button view
- ui/modals.py — Report modal
- core.py — Main Wormhole class, helpers, background loops, context menus
- commands/ — 13 command modules as mixin classes
- listeners/ — relay pipeline, edit/delete/reaction sync, typing/pin sync
## Staff System (new)
Per-network hierarchical roles replacing flat owner/staff:
Bot Owner (Red built-in) — global override
└─ Network Owner → Admin → Moderator → Helper → Member
Each role assigned per-network. Higher roles can assign lower.
Legacy staff_ids auto-migrated to ADMIN role.
## Enhanced Moderation
- Server-level ban/mute (not just user-level)
- Allowlist mode (only whitelisted servers can send)
- Mod edit and nuke (delete N messages by user)
- Anti-raid detector with auto-freeze
- Expanded automod: anti-zalgo, anti-emote-spam, anti-newline-spam
## Commands (100+)
network, settings, staff, moderation, filters, social, dm, mentions,
tos, reports, bridge, advanced (polls/afk/auto-responses/scheduled/
analytics/quiet-hours/colours/invites/announcements/blackout/portal),
debug (health/trace/testsend/relaydebug/backup/restore/version)
## Files
- 30 Python files, 5,274 lines total (was 4,782 in monolith)
- Original wormhole.py preserved for reference
- utils.py unchanged (all helpers reused)
2026-05-14 19:07:49 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
def reply_jump_view(url: str) -> discord.ui.View:
|
|
|
|
|
"""Create a View with a single URL button pointing to the replied message."""
|
|
|
|
|
view = discord.ui.View()
|
|
|
|
|
view.add_item(discord.ui.Button(
|
|
|
|
|
style=discord.ButtonStyle.link,
|
|
|
|
|
label="Jump to replied message",
|
|
|
|
|
url=url,
|
|
|
|
|
))
|
|
|
|
|
return view
|
2026-08-05 13:07:20 -04:00
|
|
|
|
|
|
|
|
|
|
|
|
|
class _ResolveButton(discord.ui.Button):
|
|
|
|
|
def __init__(self, cog, net_name: str, report_id: int):
|
|
|
|
|
super().__init__(style=discord.ButtonStyle.primary, label="Resolve")
|
|
|
|
|
self.cog = cog
|
|
|
|
|
self.net_name = net_name
|
|
|
|
|
self.report_id = report_id
|
|
|
|
|
|
|
|
|
|
async def callback(self, interaction: discord.Interaction) -> None: # type: ignore[override]
|
|
|
|
|
await self.cog._report_resolve_via_interaction(interaction, self.net_name, self.report_id)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class _DismissButton(discord.ui.Button):
|
|
|
|
|
def __init__(self, cog, net_name: str, report_id: int):
|
|
|
|
|
super().__init__(style=discord.ButtonStyle.secondary, label="Dismiss")
|
|
|
|
|
self.cog = cog
|
|
|
|
|
self.net_name = net_name
|
|
|
|
|
self.report_id = report_id
|
|
|
|
|
|
|
|
|
|
async def callback(self, interaction: discord.Interaction) -> None: # type: ignore[override]
|
|
|
|
|
await self.cog._report_dismiss_via_interaction(interaction, self.net_name, self.report_id)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class ReportActionView(discord.ui.View):
|
|
|
|
|
"""View attached to report notifications with action buttons.
|
|
|
|
|
|
|
|
|
|
The view delegates actual action handling back to the Wormhole cog so the
|
|
|
|
|
existing permission and state logic is reused.
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
def __init__(self, cog, net_name: str, report_id: int, jump_url: Optional[str] = None, *, timeout: Optional[float] = None):
|
|
|
|
|
super().__init__(timeout=timeout)
|
|
|
|
|
self.cog = cog
|
|
|
|
|
self.net_name = net_name
|
|
|
|
|
self.report_id = report_id
|
|
|
|
|
if jump_url:
|
|
|
|
|
self.add_item(discord.ui.Button(style=discord.ButtonStyle.link, label="Jump to message", url=jump_url))
|
|
|
|
|
# Action buttons
|
|
|
|
|
self.add_item(_ResolveButton(cog, net_name, report_id))
|
|
|
|
|
self.add_item(_DismissButton(cog, net_name, report_id))
|