fix: group all commands under 'wh' parent — no more flat wh-xxx commands
Commands now show as 'wh create', 'wh staff add', 'wh set relaymode' instead of 'wh-create', 'wh-staff add', 'wh-set relaymode'. - Added commands/_base.py with root 'wh' group and all 20 subgroup stubs - All 13 command mixins inherit from WormholeBase - Decorators changed: @commands.hybrid_command(name='wh-X') → @WormholeBase.wh.command(name='X') - Subgroup commands: @wh_X.command() → @WormholeBase.wh_X.command() - Removed duplicate 'wh' group from core.py (now in _base.py) - Fixed alias: 'wh-color' → 'color' for colour command
This commit is contained in:
parent
5a4421fb6c
commit
4bc143b26f
16 changed files with 297 additions and 261 deletions
|
|
@ -1,5 +1,6 @@
|
|||
"""Command modules — each is a mixin class inherited by the main Wormhole cog."""
|
||||
|
||||
from ._base import WormholeBase
|
||||
from .advanced import AdvancedCommands
|
||||
from .bridge import BridgeCommands
|
||||
from .debug import DebugCommands
|
||||
|
|
@ -15,6 +16,7 @@ from .staff import StaffCommands
|
|||
from .tos import ToSCommands
|
||||
|
||||
__all__ = [
|
||||
"WormholeBase",
|
||||
"AdvancedCommands",
|
||||
"BridgeCommands",
|
||||
"DebugCommands",
|
||||
|
|
|
|||
128
wormhole/commands/_base.py
Normal file
128
wormhole/commands/_base.py
Normal file
|
|
@ -0,0 +1,128 @@
|
|||
"""
|
||||
Root ``wh`` command group and subgroup stubs.
|
||||
|
||||
Every command mixin inherits from :class:`WormholeBase` so that
|
||||
all subcommands end up registered under the same ``wh`` parent.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from redbot.core import commands
|
||||
|
||||
|
||||
class WormholeBase:
|
||||
"""Defines the ``wh`` group and every subgroup stub.
|
||||
|
||||
Subgroups are defined here (with ``invoke_without_command=True``) so
|
||||
each mixin can reference them as ``@WormholeBase.wh_xxx.command(…)``.
|
||||
"""
|
||||
|
||||
# ── Root ───────────────────────────────────────────────────────────────
|
||||
|
||||
@commands.group(name="wh", aliases=["wormhole"], invoke_without_command=True)
|
||||
async def wh(self, ctx: commands.Context) -> None:
|
||||
"""Wormhole — the ultimate cross-server relay."""
|
||||
if ctx.invoked_subcommand is None:
|
||||
await ctx.send_help(ctx.command)
|
||||
|
||||
# ── Subgroups (alphabetical) ───────────────────────────────────────────
|
||||
|
||||
@wh.group(name="ar", aliases=["autoreply"], invoke_without_command=True)
|
||||
async def wh_ar(self, ctx: commands.Context) -> None:
|
||||
"""Auto-response triggers."""
|
||||
await ctx.send_help(ctx.command)
|
||||
|
||||
@wh.group(name="blackout", invoke_without_command=True)
|
||||
async def wh_blackout(self, ctx: commands.Context) -> None:
|
||||
"""Scheduled freeze windows."""
|
||||
await ctx.send_help(ctx.command)
|
||||
|
||||
@wh.group(name="bm", aliases=["bookmark"], invoke_without_command=True)
|
||||
async def wh_bm(self, ctx: commands.Context) -> None:
|
||||
"""Message bookmarks."""
|
||||
await ctx.send_help(ctx.command)
|
||||
|
||||
@wh.group(name="bridge", invoke_without_command=True)
|
||||
async def wh_bridge(self, ctx: commands.Context) -> None:
|
||||
"""Cross-network bridging."""
|
||||
await ctx.send_help(ctx.command)
|
||||
|
||||
@wh.group(name="debug", invoke_without_command=True)
|
||||
async def wh_debug(self, ctx: commands.Context) -> None:
|
||||
"""Debug and diagnostic tools."""
|
||||
await ctx.send_help(ctx.command)
|
||||
|
||||
@wh.group(name="dm", invoke_without_command=True)
|
||||
async def wh_dm(self, ctx: commands.Context) -> None:
|
||||
"""DM relay — receive network messages in your DMs."""
|
||||
await ctx.send_help(ctx.command)
|
||||
|
||||
@wh.group(name="filter", invoke_without_command=True)
|
||||
async def wh_filter(self, ctx: commands.Context) -> None:
|
||||
"""Manage content filters and automod."""
|
||||
await ctx.send_help(ctx.command)
|
||||
|
||||
@wh.group(name="hl", aliases=["highlight"], invoke_without_command=True)
|
||||
async def wh_hl(self, ctx: commands.Context) -> None:
|
||||
"""Keyword highlight notifications."""
|
||||
await ctx.send_help(ctx.command)
|
||||
|
||||
@wh.group(name="invite", invoke_without_command=True)
|
||||
async def wh_invite(self, ctx: commands.Context) -> None:
|
||||
"""Network invite codes."""
|
||||
await ctx.send_help(ctx.command)
|
||||
|
||||
@wh.group(name="karma", invoke_without_command=True)
|
||||
async def wh_karma(self, ctx: commands.Context) -> None:
|
||||
"""Karma system commands."""
|
||||
await ctx.send_help(ctx.command)
|
||||
|
||||
@wh.group(name="mention", aliases=["mentions"], invoke_without_command=True)
|
||||
async def wh_mention(self, ctx: commands.Context) -> None:
|
||||
"""Configure mention behaviour."""
|
||||
await ctx.send_help(ctx.command)
|
||||
|
||||
@wh.group(name="mirror", invoke_without_command=True)
|
||||
async def wh_mirror(self, ctx: commands.Context) -> None:
|
||||
"""Mirror channels — exact copy of relay to an extra channel."""
|
||||
await ctx.send_help(ctx.command)
|
||||
|
||||
@wh.group(name="mod", invoke_without_command=True)
|
||||
async def wh_mod(self, ctx: commands.Context) -> None:
|
||||
"""Network moderation tools."""
|
||||
await ctx.send_help(ctx.command)
|
||||
|
||||
@wh.group(name="poll", invoke_without_command=True)
|
||||
async def wh_poll(self, ctx: commands.Context) -> None:
|
||||
"""Network-wide polls."""
|
||||
await ctx.send_help(ctx.command)
|
||||
|
||||
@wh.group(name="report", invoke_without_command=True)
|
||||
async def wh_report(self, ctx: commands.Context) -> None:
|
||||
"""Network report system."""
|
||||
await ctx.send_help(ctx.command)
|
||||
|
||||
@wh.group(name="rules", aliases=["tos", "terms"], invoke_without_command=True)
|
||||
async def wh_rules(self, ctx: commands.Context) -> None:
|
||||
"""Network rules / Terms of Service."""
|
||||
await ctx.send_help(ctx.command)
|
||||
|
||||
@wh.group(name="schedule", invoke_without_command=True)
|
||||
async def wh_schedule(self, ctx: commands.Context) -> None:
|
||||
"""Scheduled messages."""
|
||||
await ctx.send_help(ctx.command)
|
||||
|
||||
@wh.group(name="set", invoke_without_command=True)
|
||||
async def wh_set(self, ctx: commands.Context) -> None:
|
||||
"""Configure network settings."""
|
||||
await ctx.send_help(ctx.command)
|
||||
|
||||
@wh.group(name="staff", invoke_without_command=True)
|
||||
async def wh_staff(self, ctx: commands.Context) -> None:
|
||||
"""Manage network staff — add, remove, list, promote, demote."""
|
||||
await ctx.send_help(ctx.command)
|
||||
|
||||
@wh.group(name="star", aliases=["starboard"], invoke_without_command=True)
|
||||
async def wh_star(self, ctx: commands.Context) -> None:
|
||||
"""Starboard commands."""
|
||||
await ctx.send_help(ctx.command)
|
||||
|
|
@ -15,19 +15,15 @@ from ..utils import (
|
|||
ok_embed, err_embed, info_embed, warn_embed, announce_embed,
|
||||
truncate, generate_invite_code, human_timedelta, COLOUR_INFO,
|
||||
)
|
||||
from ._base import WormholeBase
|
||||
|
||||
|
||||
class AdvancedCommands:
|
||||
class AdvancedCommands(WormholeBase):
|
||||
"""Mixin — advanced features."""
|
||||
|
||||
# ── Polls ──────────────────────────────────────────────────────────────
|
||||
|
||||
@commands.group(name="wh-poll", aliases=["whpoll"], invoke_without_command=True)
|
||||
async def wh_poll(self, ctx: commands.Context) -> None:
|
||||
"""Network-wide polls."""
|
||||
await ctx.send_help(ctx.command)
|
||||
|
||||
@wh_poll.command(name="create")
|
||||
@WormholeBase.wh_poll.command(name="create")
|
||||
@requires_role(Role.MODERATOR)
|
||||
async def wh_poll_create(self, ctx: commands.Context, name: str, duration_minutes: int, question: str, *, options: str) -> None:
|
||||
"""Create a poll. Options separated by ``|``.
|
||||
|
|
@ -66,7 +62,7 @@ class AdvancedCommands:
|
|||
pass
|
||||
await ctx.send(embed=ok_embed(f"Poll `{poll_id}` created in `{name}`."))
|
||||
|
||||
@wh_poll.command(name="vote")
|
||||
@WormholeBase.wh_poll.command(name="vote")
|
||||
async def wh_poll_vote(self, ctx: commands.Context, name: str, poll_id: str, choice: int) -> None:
|
||||
"""Vote in a poll (choice = option number, 1-based)."""
|
||||
nd = await self._net(name)
|
||||
|
|
@ -88,7 +84,7 @@ class AdvancedCommands:
|
|||
p.setdefault("votes", {}).setdefault(idx, []).append(uid)
|
||||
await ctx.send(embed=ok_embed(f"Voted for **{poll['options'][choice-1]}**."), delete_after=5)
|
||||
|
||||
@wh_poll.command(name="results")
|
||||
@WormholeBase.wh_poll.command(name="results")
|
||||
async def wh_poll_results(self, ctx: commands.Context, name: str, poll_id: str) -> None:
|
||||
"""View current poll results."""
|
||||
nd = await self._net(name)
|
||||
|
|
@ -100,7 +96,7 @@ class AdvancedCommands:
|
|||
results = self._format_poll_results(poll)
|
||||
await ctx.send(embed=info_embed(results, title=f"📊 {poll['question']}"))
|
||||
|
||||
@wh_poll.command(name="end")
|
||||
@WormholeBase.wh_poll.command(name="end")
|
||||
@requires_role(Role.MODERATOR)
|
||||
async def wh_poll_end(self, ctx: commands.Context, name: str, poll_id: str) -> None:
|
||||
"""End a poll early."""
|
||||
|
|
@ -124,7 +120,7 @@ class AdvancedCommands:
|
|||
|
||||
# ── AFK ────────────────────────────────────────────────────────────────
|
||||
|
||||
@commands.hybrid_command(name="wh-afk")
|
||||
@WormholeBase.wh.command(name="afk")
|
||||
async def wh_afk(self, ctx: commands.Context, name: str, *, reason: str = "AFK") -> None:
|
||||
"""Set your AFK status in a network."""
|
||||
nd = await self._net(name)
|
||||
|
|
@ -139,12 +135,7 @@ class AdvancedCommands:
|
|||
|
||||
# ── Auto-responses ─────────────────────────────────────────────────────
|
||||
|
||||
@commands.group(name="wh-ar", aliases=["whar"], invoke_without_command=True)
|
||||
async def wh_ar(self, ctx: commands.Context) -> None:
|
||||
"""Auto-response triggers."""
|
||||
await ctx.send_help(ctx.command)
|
||||
|
||||
@wh_ar.command(name="add")
|
||||
@WormholeBase.wh_ar.command(name="add")
|
||||
@requires_role(Role.ADMIN)
|
||||
async def wh_ar_add(self, ctx: commands.Context, name: str, trigger: str, *, reply: str) -> None:
|
||||
"""Add an auto-response. Use ``regex:pattern`` for regex triggers."""
|
||||
|
|
@ -165,7 +156,7 @@ class AdvancedCommands:
|
|||
}
|
||||
await ctx.send(embed=ok_embed(f"Auto-response added for `{trigger}`."))
|
||||
|
||||
@wh_ar.command(name="remove", aliases=["rm"])
|
||||
@WormholeBase.wh_ar.command(name="remove", aliases=["rm"])
|
||||
@requires_role(Role.ADMIN)
|
||||
async def wh_ar_rm(self, ctx: commands.Context, name: str, *, trigger: str) -> None:
|
||||
"""Remove an auto-response."""
|
||||
|
|
@ -173,7 +164,7 @@ class AdvancedCommands:
|
|||
ns[name].get("auto_responses", {}).pop(trigger, None)
|
||||
await ctx.send(embed=ok_embed(f"Auto-response removed for `{trigger}`."))
|
||||
|
||||
@wh_ar.command(name="list")
|
||||
@WormholeBase.wh_ar.command(name="list")
|
||||
@requires_role(Role.HELPER)
|
||||
async def wh_ar_list(self, ctx: commands.Context, name: str) -> None:
|
||||
"""List auto-responses."""
|
||||
|
|
@ -191,12 +182,7 @@ class AdvancedCommands:
|
|||
|
||||
# ── Scheduled messages ─────────────────────────────────────────────────
|
||||
|
||||
@commands.group(name="wh-schedule", aliases=["whschedule"], invoke_without_command=True)
|
||||
async def wh_schedule(self, ctx: commands.Context) -> None:
|
||||
"""Scheduled messages."""
|
||||
await ctx.send_help(ctx.command)
|
||||
|
||||
@wh_schedule.command(name="add")
|
||||
@WormholeBase.wh_schedule.command(name="add")
|
||||
@requires_role(Role.ADMIN)
|
||||
async def wh_schedule_add(self, ctx: commands.Context, name: str, minutes_from_now: int, *, content: str) -> None:
|
||||
"""Schedule a message to be sent in N minutes."""
|
||||
|
|
@ -209,7 +195,7 @@ class AdvancedCommands:
|
|||
})
|
||||
await ctx.send(embed=ok_embed(f"Message scheduled for {minutes_from_now} minutes from now."))
|
||||
|
||||
@wh_schedule.command(name="list")
|
||||
@WormholeBase.wh_schedule.command(name="list")
|
||||
@requires_role(Role.HELPER)
|
||||
async def wh_schedule_list(self, ctx: commands.Context, name: str) -> None:
|
||||
"""List scheduled messages."""
|
||||
|
|
@ -224,7 +210,7 @@ class AdvancedCommands:
|
|||
lines.append(f"**{i}.** {sm.get('send_at_iso', '?')[:16]} — {truncate(sm.get('content', ''), 60)}")
|
||||
await ctx.send(embed=info_embed("\n".join(lines), title=f"📅 Scheduled — {name}"))
|
||||
|
||||
@wh_schedule.command(name="clear")
|
||||
@WormholeBase.wh_schedule.command(name="clear")
|
||||
@requires_role(Role.ADMIN)
|
||||
async def wh_schedule_clear(self, ctx: commands.Context, name: str) -> None:
|
||||
"""Clear all scheduled messages."""
|
||||
|
|
@ -234,7 +220,7 @@ class AdvancedCommands:
|
|||
|
||||
# ── Analytics ──────────────────────────────────────────────────────────
|
||||
|
||||
@commands.hybrid_command(name="wh-analytics")
|
||||
@WormholeBase.wh.command(name="analytics")
|
||||
@requires_role(Role.HELPER)
|
||||
async def wh_analytics(self, ctx: commands.Context, name: str) -> None:
|
||||
"""View network analytics dashboard."""
|
||||
|
|
@ -269,7 +255,7 @@ class AdvancedCommands:
|
|||
|
||||
# ── Quiet hours ────────────────────────────────────────────────────────
|
||||
|
||||
@commands.hybrid_command(name="wh-quiet")
|
||||
@WormholeBase.wh.command(name="quiet")
|
||||
async def wh_quiet(self, ctx: commands.Context, name: str, start_hour: int, end_hour: int, tz_offset: int = 0) -> None:
|
||||
"""Set quiet hours — DM relay pauses during this window.
|
||||
|
||||
|
|
@ -285,7 +271,7 @@ class AdvancedCommands:
|
|||
}
|
||||
await ctx.send(embed=ok_embed(f"Quiet hours set: {start_hour}:00–{end_hour}:00 (UTC{tz_offset:+d})"))
|
||||
|
||||
@commands.hybrid_command(name="wh-unquiet")
|
||||
@WormholeBase.wh.command(name="unquiet")
|
||||
async def wh_unquiet(self, ctx: commands.Context, name: str) -> None:
|
||||
"""Remove your quiet hours."""
|
||||
async with self.config.networks() as ns:
|
||||
|
|
@ -294,7 +280,7 @@ class AdvancedCommands:
|
|||
|
||||
# ── User colours ───────────────────────────────────────────────────────
|
||||
|
||||
@commands.hybrid_command(name="wh-colour", aliases=["wh-color"])
|
||||
@WormholeBase.wh.command(name="colour", aliases=["color"])
|
||||
async def wh_colour(self, ctx: commands.Context, name: str, hex_code: str = None) -> None:
|
||||
"""Set your name colour in embed mode (hex, e.g. ``#ff5733``)."""
|
||||
if hex_code:
|
||||
|
|
@ -311,12 +297,7 @@ class AdvancedCommands:
|
|||
|
||||
# ── Invites ────────────────────────────────────────────────────────────
|
||||
|
||||
@commands.group(name="wh-invite", aliases=["whinvite"], invoke_without_command=True)
|
||||
async def wh_invite(self, ctx: commands.Context) -> None:
|
||||
"""Network invite codes."""
|
||||
await ctx.send_help(ctx.command)
|
||||
|
||||
@wh_invite.command(name="create")
|
||||
@WormholeBase.wh_invite.command(name="create")
|
||||
@requires_role(Role.ADMIN)
|
||||
async def wh_invite_create(self, ctx: commands.Context, name: str, max_uses: int = 0) -> None:
|
||||
"""Create an invite code (``max_uses`` 0 = unlimited)."""
|
||||
|
|
@ -330,7 +311,7 @@ class AdvancedCommands:
|
|||
}
|
||||
await ctx.send(embed=ok_embed(f"Invite code: `{code}`\nMax uses: {'unlimited' if max_uses == 0 else max_uses}"))
|
||||
|
||||
@wh_invite.command(name="vanity")
|
||||
@WormholeBase.wh_invite.command(name="vanity")
|
||||
@requires_role(Role.OWNER)
|
||||
async def wh_invite_vanity(self, ctx: commands.Context, name: str, code: str) -> None:
|
||||
"""Set a vanity invite code."""
|
||||
|
|
@ -340,7 +321,7 @@ class AdvancedCommands:
|
|||
ns[name]["vanity_invite"] = code
|
||||
await ctx.send(embed=ok_embed(f"Vanity invite set: `{code}`"))
|
||||
|
||||
@wh_invite.command(name="list")
|
||||
@WormholeBase.wh_invite.command(name="list")
|
||||
@requires_role(Role.ADMIN)
|
||||
async def wh_invite_list(self, ctx: commands.Context, name: str) -> None:
|
||||
"""List all invite codes."""
|
||||
|
|
@ -360,7 +341,7 @@ class AdvancedCommands:
|
|||
lines.append(f"\n✨ Vanity: `{vanity}`")
|
||||
await ctx.send(embed=info_embed("\n".join(lines), title=f"🔗 Invites — {name}"))
|
||||
|
||||
@wh_invite.command(name="revoke")
|
||||
@WormholeBase.wh_invite.command(name="revoke")
|
||||
@requires_role(Role.ADMIN)
|
||||
async def wh_invite_revoke(self, ctx: commands.Context, name: str, code: str) -> None:
|
||||
"""Revoke an invite code."""
|
||||
|
|
@ -370,7 +351,7 @@ class AdvancedCommands:
|
|||
|
||||
# ── Announcements ──────────────────────────────────────────────────────
|
||||
|
||||
@commands.hybrid_command(name="wh-announce")
|
||||
@WormholeBase.wh.command(name="announce")
|
||||
@requires_role(Role.ADMIN)
|
||||
async def wh_announce(self, ctx: commands.Context, name: str, *, message: str) -> None:
|
||||
"""Broadcast an announcement to all channels in the network."""
|
||||
|
|
@ -392,12 +373,7 @@ class AdvancedCommands:
|
|||
|
||||
# ── Blackout schedules ─────────────────────────────────────────────────
|
||||
|
||||
@commands.group(name="wh-blackout", aliases=["whblackout"], invoke_without_command=True)
|
||||
async def wh_blackout(self, ctx: commands.Context) -> None:
|
||||
"""Scheduled freeze windows."""
|
||||
await ctx.send_help(ctx.command)
|
||||
|
||||
@wh_blackout.command(name="add")
|
||||
@WormholeBase.wh_blackout.command(name="add")
|
||||
@requires_role(Role.ADMIN)
|
||||
async def wh_blackout_add(self, ctx: commands.Context, name: str, start_hour: int, end_hour: int, *, days: str = "0,1,2,3,4,5,6") -> None:
|
||||
"""Add a blackout schedule. Days: 0=Mon … 6=Sun."""
|
||||
|
|
@ -410,7 +386,7 @@ class AdvancedCommands:
|
|||
})
|
||||
await ctx.send(embed=ok_embed(f"Blackout added: {start_hour}:00–{end_hour}:00 UTC on days {day_list}"))
|
||||
|
||||
@wh_blackout.command(name="clear")
|
||||
@WormholeBase.wh_blackout.command(name="clear")
|
||||
@requires_role(Role.ADMIN)
|
||||
async def wh_blackout_clear(self, ctx: commands.Context, name: str) -> None:
|
||||
"""Clear all blackout schedules."""
|
||||
|
|
@ -420,7 +396,7 @@ class AdvancedCommands:
|
|||
|
||||
# ── Portal embed ───────────────────────────────────────────────────────
|
||||
|
||||
@commands.hybrid_command(name="wh-portal")
|
||||
@WormholeBase.wh.command(name="portal")
|
||||
@requires_role(Role.ADMIN)
|
||||
async def wh_portal(self, ctx: commands.Context, name: str) -> None:
|
||||
"""Post a self-updating portal embed in this channel."""
|
||||
|
|
|
|||
|
|
@ -7,17 +7,13 @@ from redbot.core import commands
|
|||
|
||||
from ..models.permissions import Role, requires_role
|
||||
from ..utils import ok_embed, err_embed, info_embed, COLOUR_INFO
|
||||
from ._base import WormholeBase
|
||||
|
||||
|
||||
class BridgeCommands:
|
||||
class BridgeCommands(WormholeBase):
|
||||
"""Mixin — network bridging and mirror channels."""
|
||||
|
||||
@commands.group(name="wh-bridge", aliases=["whbridge"], invoke_without_command=True)
|
||||
async def wh_bridge(self, ctx: commands.Context) -> None:
|
||||
"""Cross-network bridging."""
|
||||
await ctx.send_help(ctx.command)
|
||||
|
||||
@wh_bridge.command(name="link")
|
||||
@WormholeBase.wh_bridge.command(name="link")
|
||||
@requires_role(Role.OWNER)
|
||||
async def wh_bridge_link(self, ctx: commands.Context, source: str, target: str) -> None:
|
||||
"""Bridge messages from one network to another (one-way)."""
|
||||
|
|
@ -37,7 +33,7 @@ class BridgeCommands:
|
|||
await ctx.send(embed=ok_embed(f"Bridge: `{source}` → `{target}` (one-way)."))
|
||||
await self._audit(source, "bridge_link", str(ctx.author), target)
|
||||
|
||||
@wh_bridge.command(name="unlink")
|
||||
@WormholeBase.wh_bridge.command(name="unlink")
|
||||
@requires_role(Role.OWNER)
|
||||
async def wh_bridge_unlink(self, ctx: commands.Context, source: str, target: str) -> None:
|
||||
"""Remove a bridge."""
|
||||
|
|
@ -53,7 +49,7 @@ class BridgeCommands:
|
|||
await ctx.send(embed=ok_embed(f"Bridge `{source}` → `{target}` removed."))
|
||||
await self._audit(source, "bridge_unlink", str(ctx.author), target)
|
||||
|
||||
@wh_bridge.command(name="list")
|
||||
@WormholeBase.wh_bridge.command(name="list")
|
||||
async def wh_bridge_list(self, ctx: commands.Context, name: str) -> None:
|
||||
"""List bridges for a network."""
|
||||
nd = await self._net(name)
|
||||
|
|
@ -70,12 +66,7 @@ class BridgeCommands:
|
|||
|
||||
# ── Mirror channels ────────────────────────────────────────────────────
|
||||
|
||||
@commands.group(name="wh-mirror", aliases=["whmirror"], invoke_without_command=True)
|
||||
async def wh_mirror(self, ctx: commands.Context) -> None:
|
||||
"""Mirror channels — exact copy of relay to an extra channel."""
|
||||
await ctx.send_help(ctx.command)
|
||||
|
||||
@wh_mirror.command(name="add")
|
||||
@WormholeBase.wh_mirror.command(name="add")
|
||||
@requires_role(Role.ADMIN)
|
||||
async def wh_mirror_add(self, ctx: commands.Context, name: str, channel: discord.TextChannel) -> None:
|
||||
"""Add a mirror channel."""
|
||||
|
|
@ -85,7 +76,7 @@ class BridgeCommands:
|
|||
mirrors.append(channel.id)
|
||||
await ctx.send(embed=ok_embed(f"{channel.mention} added as mirror for `{name}`."))
|
||||
|
||||
@wh_mirror.command(name="remove", aliases=["rm"])
|
||||
@WormholeBase.wh_mirror.command(name="remove", aliases=["rm"])
|
||||
@requires_role(Role.ADMIN)
|
||||
async def wh_mirror_rm(self, ctx: commands.Context, name: str, channel: discord.TextChannel) -> None:
|
||||
"""Remove a mirror channel."""
|
||||
|
|
@ -95,7 +86,7 @@ class BridgeCommands:
|
|||
mirrors.remove(channel.id)
|
||||
await ctx.send(embed=ok_embed(f"{channel.mention} removed from mirrors for `{name}`."))
|
||||
|
||||
@wh_mirror.command(name="list")
|
||||
@WormholeBase.wh_mirror.command(name="list")
|
||||
async def wh_mirror_list(self, ctx: commands.Context, name: str) -> None:
|
||||
"""List mirror channels."""
|
||||
nd = await self._net(name)
|
||||
|
|
|
|||
|
|
@ -12,17 +12,13 @@ from redbot.core import checks, commands
|
|||
|
||||
from ..models.permissions import Role, has_role, requires_role
|
||||
from ..utils import ok_embed, err_embed, info_embed, warn_embed, COLOUR_INFO, human_timedelta
|
||||
from ._base import WormholeBase
|
||||
|
||||
|
||||
class DebugCommands:
|
||||
class DebugCommands(WormholeBase):
|
||||
"""Mixin — debug, diagnostics, backup/restore."""
|
||||
|
||||
@commands.group(name="wh-debug", aliases=["whdebug"], invoke_without_command=True)
|
||||
async def wh_debug(self, ctx: commands.Context) -> None:
|
||||
"""Debug and diagnostic tools."""
|
||||
await ctx.send_help(ctx.command)
|
||||
|
||||
@wh_debug.command(name="health")
|
||||
@WormholeBase.wh_debug.command(name="health")
|
||||
@requires_role(Role.HELPER)
|
||||
async def wh_debug_health(self, ctx: commands.Context, name: str) -> None:
|
||||
"""Check network health — permissions, webhooks, channel status."""
|
||||
|
|
@ -62,7 +58,7 @@ class DebugCommands:
|
|||
em.set_footer(text=f"{healthy}/{len(channels)} healthy · Last check: {nd.get('last_health_check', 'never')[:16]}")
|
||||
await ctx.send(embed=em)
|
||||
|
||||
@wh_debug.command(name="trace")
|
||||
@WormholeBase.wh_debug.command(name="trace")
|
||||
@requires_role(Role.ADMIN)
|
||||
async def wh_debug_trace(self, ctx: commands.Context) -> None:
|
||||
"""Toggle trace mode for this channel — logs all relay decisions."""
|
||||
|
|
@ -73,7 +69,7 @@ class DebugCommands:
|
|||
self._trace_channels.add(ctx.channel.id)
|
||||
await ctx.send(embed=ok_embed("Trace mode **enabled** — relay decisions will be logged here."))
|
||||
|
||||
@wh_debug.command(name="testsend")
|
||||
@WormholeBase.wh_debug.command(name="testsend")
|
||||
@requires_role(Role.ADMIN)
|
||||
async def wh_debug_testsend(self, ctx: commands.Context, name: str) -> None:
|
||||
"""Send a test message through the relay."""
|
||||
|
|
@ -97,7 +93,7 @@ class DebugCommands:
|
|||
await ctx.send(embed=warn_embed(f"Failed to send to {ch.mention}: {exc}"))
|
||||
await ctx.send(embed=ok_embed(f"Test message sent to {sent} channels."))
|
||||
|
||||
@wh_debug.command(name="relaydebug")
|
||||
@WormholeBase.wh_debug.command(name="relaydebug")
|
||||
@requires_role(Role.ADMIN)
|
||||
async def wh_debug_relaydebug(self, ctx: commands.Context, name: str) -> None:
|
||||
"""Show detailed relay pipeline state for diagnostics."""
|
||||
|
|
@ -120,7 +116,7 @@ class DebugCommands:
|
|||
|
||||
# ── Backup / Restore ───────────────────────────────────────────────────
|
||||
|
||||
@wh_debug.command(name="backup")
|
||||
@WormholeBase.wh_debug.command(name="backup")
|
||||
@requires_role(Role.OWNER)
|
||||
async def wh_debug_backup(self, ctx: commands.Context, name: str) -> None:
|
||||
"""Export network config as a JSON file."""
|
||||
|
|
@ -139,7 +135,7 @@ class DebugCommands:
|
|||
file=discord.File(buf, filename=f"wormhole_{name}_backup.json"),
|
||||
)
|
||||
|
||||
@wh_debug.command(name="restore")
|
||||
@WormholeBase.wh_debug.command(name="restore")
|
||||
@checks.is_owner()
|
||||
async def wh_debug_restore(self, ctx: commands.Context, name: str) -> None:
|
||||
"""Restore a network from a JSON backup (attach file to message)."""
|
||||
|
|
@ -159,7 +155,7 @@ class DebugCommands:
|
|||
|
||||
# ── Version ────────────────────────────────────────────────────────────
|
||||
|
||||
@commands.hybrid_command(name="wh-version")
|
||||
@WormholeBase.wh.command(name="version")
|
||||
async def wh_version(self, ctx: commands.Context) -> None:
|
||||
"""Show Wormhole cog version."""
|
||||
nets = await self.config.networks()
|
||||
|
|
|
|||
|
|
@ -7,17 +7,13 @@ from redbot.core import commands
|
|||
|
||||
from ..models.permissions import Role, requires_role
|
||||
from ..utils import ok_embed, err_embed, info_embed, dm_embed, truncate
|
||||
from ._base import WormholeBase
|
||||
|
||||
|
||||
class DMCommands:
|
||||
class DMCommands(WormholeBase):
|
||||
"""Mixin — DM relay management."""
|
||||
|
||||
@commands.group(name="wh-dm", aliases=["whdm"], invoke_without_command=True)
|
||||
async def wh_dm(self, ctx: commands.Context) -> None:
|
||||
"""DM relay — receive network messages in your DMs."""
|
||||
await ctx.send_help(ctx.command)
|
||||
|
||||
@wh_dm.command(name="enable")
|
||||
@WormholeBase.wh_dm.command(name="enable")
|
||||
@requires_role(Role.ADMIN)
|
||||
async def wh_dm_enable(self, ctx: commands.Context, name: str, enabled: bool = True) -> None:
|
||||
"""Enable or disable DM relay for a network."""
|
||||
|
|
@ -25,7 +21,7 @@ class DMCommands:
|
|||
ns[name]["dm_enabled"] = enabled
|
||||
await ctx.send(embed=ok_embed(f"DM relay {'enabled' if enabled else 'disabled'} for `{name}`."))
|
||||
|
||||
@wh_dm.command(name="subscribe", aliases=["sub"])
|
||||
@WormholeBase.wh_dm.command(name="subscribe", aliases=["sub"])
|
||||
async def wh_dm_sub(self, ctx: commands.Context, name: str) -> None:
|
||||
"""Subscribe to receive network messages via DM."""
|
||||
nd = await self._net(name)
|
||||
|
|
@ -40,7 +36,7 @@ class DMCommands:
|
|||
subs.append(ctx.author.id)
|
||||
await ctx.send(embed=ok_embed(f"Subscribed to DM relay for `{name}`."))
|
||||
|
||||
@wh_dm.command(name="unsubscribe", aliases=["unsub"])
|
||||
@WormholeBase.wh_dm.command(name="unsubscribe", aliases=["unsub"])
|
||||
async def wh_dm_unsub(self, ctx: commands.Context, name: str) -> None:
|
||||
"""Unsubscribe from DM relay."""
|
||||
async with self.config.networks() as ns:
|
||||
|
|
@ -49,7 +45,7 @@ class DMCommands:
|
|||
subs.remove(ctx.author.id)
|
||||
await ctx.send(embed=ok_embed(f"Unsubscribed from DM relay for `{name}`."))
|
||||
|
||||
@wh_dm.command(name="mode")
|
||||
@WormholeBase.wh_dm.command(name="mode")
|
||||
@requires_role(Role.ADMIN)
|
||||
async def wh_dm_mode(self, ctx: commands.Context, name: str, mode: str) -> None:
|
||||
"""Set DM relay mode: ``embed``, ``compact``, or ``plain``."""
|
||||
|
|
@ -59,7 +55,7 @@ class DMCommands:
|
|||
ns[name]["dm_relay_mode"] = mode
|
||||
await ctx.send(embed=ok_embed(f"DM relay mode set to **{mode}** for `{name}`."))
|
||||
|
||||
@wh_dm.command(name="send")
|
||||
@WormholeBase.wh_dm.command(name="send")
|
||||
async def wh_dm_send(self, ctx: commands.Context, name: str, *, message: str) -> None:
|
||||
"""Send a message to the network from your DMs."""
|
||||
nd = await self._net(name)
|
||||
|
|
@ -83,7 +79,7 @@ class DMCommands:
|
|||
pass
|
||||
await ctx.send(embed=ok_embed("Message sent to the network."))
|
||||
|
||||
@wh_dm.command(name="ignore")
|
||||
@WormholeBase.wh_dm.command(name="ignore")
|
||||
async def wh_dm_ignore(self, ctx: commands.Context, name: str, user: discord.User) -> None:
|
||||
"""Ignore a user in DM relay (you won't see their messages)."""
|
||||
async with self.config.networks() as ns:
|
||||
|
|
@ -94,7 +90,7 @@ class DMCommands:
|
|||
user_ignores.append(user.id)
|
||||
await ctx.send(embed=ok_embed(f"{user.display_name} ignored in DM relay for `{name}`."))
|
||||
|
||||
@wh_dm.command(name="unignore")
|
||||
@WormholeBase.wh_dm.command(name="unignore")
|
||||
async def wh_dm_unignore(self, ctx: commands.Context, name: str, user: discord.User) -> None:
|
||||
"""Stop ignoring a user in DM relay."""
|
||||
async with self.config.networks() as ns:
|
||||
|
|
|
|||
|
|
@ -7,19 +7,15 @@ from redbot.core import commands
|
|||
|
||||
from ..models.permissions import Role, requires_role
|
||||
from ..utils import ok_embed, err_embed, info_embed, COLOUR_INFO
|
||||
from ._base import WormholeBase
|
||||
|
||||
|
||||
class FilterCommands:
|
||||
class FilterCommands(WormholeBase):
|
||||
"""Mixin — content filters and automod configuration."""
|
||||
|
||||
@commands.group(name="wh-filter", aliases=["whfilter"], invoke_without_command=True)
|
||||
async def wh_filter(self, ctx: commands.Context) -> None:
|
||||
"""Manage content filters and automod."""
|
||||
await ctx.send_help(ctx.command)
|
||||
|
||||
# ── Word filters ───────────────────────────────────────────────────────
|
||||
|
||||
@wh_filter.command(name="addword")
|
||||
@WormholeBase.wh_filter.command(name="addword")
|
||||
@requires_role(Role.MODERATOR)
|
||||
async def wh_filter_addword(self, ctx: commands.Context, name: str, *, word: str) -> None:
|
||||
"""Add a word to the filter list."""
|
||||
|
|
@ -30,7 +26,7 @@ class FilterCommands:
|
|||
await ctx.send(embed=ok_embed(f"Word `{word}` added to filters for `{name}`."))
|
||||
await self._audit(name, "filter_add", str(ctx.author), word)
|
||||
|
||||
@wh_filter.command(name="rmword")
|
||||
@WormholeBase.wh_filter.command(name="rmword")
|
||||
@requires_role(Role.MODERATOR)
|
||||
async def wh_filter_rmword(self, ctx: commands.Context, name: str, *, word: str) -> None:
|
||||
"""Remove a word from the filter list."""
|
||||
|
|
@ -39,7 +35,7 @@ class FilterCommands:
|
|||
ns[name]["word_filters"] = [w for w in wf if w.lower() != word.lower()]
|
||||
await ctx.send(embed=ok_embed(f"Word `{word}` removed from filters for `{name}`."))
|
||||
|
||||
@wh_filter.command(name="addregex")
|
||||
@WormholeBase.wh_filter.command(name="addregex")
|
||||
@requires_role(Role.ADMIN)
|
||||
async def wh_filter_addregex(self, ctx: commands.Context, name: str, *, pattern: str) -> None:
|
||||
"""Add a regex pattern to the filter list."""
|
||||
|
|
@ -55,7 +51,7 @@ class FilterCommands:
|
|||
await ctx.send(embed=ok_embed(f"Regex `{pattern}` added to filters for `{name}`."))
|
||||
await self._audit(name, "regex_add", str(ctx.author), pattern)
|
||||
|
||||
@wh_filter.command(name="rmregex")
|
||||
@WormholeBase.wh_filter.command(name="rmregex")
|
||||
@requires_role(Role.ADMIN)
|
||||
async def wh_filter_rmregex(self, ctx: commands.Context, name: str, *, pattern: str) -> None:
|
||||
"""Remove a regex pattern from the filter list."""
|
||||
|
|
@ -65,7 +61,7 @@ class FilterCommands:
|
|||
rf.remove(pattern)
|
||||
await ctx.send(embed=ok_embed(f"Regex removed from filters for `{name}`."))
|
||||
|
||||
@wh_filter.command(name="list")
|
||||
@WormholeBase.wh_filter.command(name="list")
|
||||
@requires_role(Role.HELPER)
|
||||
async def wh_filter_list(self, ctx: commands.Context, name: str) -> None:
|
||||
"""List all active filters."""
|
||||
|
|
@ -89,7 +85,7 @@ class FilterCommands:
|
|||
|
||||
# ── Automod ────────────────────────────────────────────────────────────
|
||||
|
||||
@wh_filter.command(name="automod")
|
||||
@WormholeBase.wh_filter.command(name="automod")
|
||||
@requires_role(Role.ADMIN)
|
||||
async def wh_filter_automod(self, ctx: commands.Context, name: str, feature: str, enabled: bool) -> None:
|
||||
"""Toggle automod features.
|
||||
|
|
@ -131,7 +127,7 @@ class FilterCommands:
|
|||
else:
|
||||
self.raid_detectors.pop(name, None)
|
||||
|
||||
@wh_filter.command(name="automod-set")
|
||||
@WormholeBase.wh_filter.command(name="automod-set")
|
||||
@requires_role(Role.ADMIN)
|
||||
async def wh_filter_automod_set(self, ctx: commands.Context, name: str, key: str, value: str) -> None:
|
||||
"""Set an automod parameter.
|
||||
|
|
@ -155,7 +151,7 @@ class FilterCommands:
|
|||
|
||||
# ── Attachment filters ─────────────────────────────────────────────────
|
||||
|
||||
@wh_filter.command(name="blockext")
|
||||
@WormholeBase.wh_filter.command(name="blockext")
|
||||
@requires_role(Role.ADMIN)
|
||||
async def wh_filter_blockext(self, ctx: commands.Context, name: str, ext: str) -> None:
|
||||
"""Block a file extension (e.g. ``.exe``)."""
|
||||
|
|
@ -167,7 +163,7 @@ class FilterCommands:
|
|||
exts.append(ext)
|
||||
await ctx.send(embed=ok_embed(f"Extension `{ext}` blocked for `{name}`."))
|
||||
|
||||
@wh_filter.command(name="unblockext")
|
||||
@WormholeBase.wh_filter.command(name="unblockext")
|
||||
@requires_role(Role.ADMIN)
|
||||
async def wh_filter_unblockext(self, ctx: commands.Context, name: str, ext: str) -> None:
|
||||
"""Unblock a file extension."""
|
||||
|
|
@ -179,7 +175,7 @@ class FilterCommands:
|
|||
exts.remove(ext)
|
||||
await ctx.send(embed=ok_embed(f"Extension `{ext}` unblocked for `{name}`."))
|
||||
|
||||
@wh_filter.command(name="maxfilesize")
|
||||
@WormholeBase.wh_filter.command(name="maxfilesize")
|
||||
@requires_role(Role.ADMIN)
|
||||
async def wh_filter_maxfilesize(self, ctx: commands.Context, name: str, mb: float = 0) -> None:
|
||||
"""Set max file size in MB (0 to disable)."""
|
||||
|
|
|
|||
|
|
@ -7,17 +7,13 @@ from redbot.core import commands
|
|||
|
||||
from ..models.permissions import Role, requires_role
|
||||
from ..utils import ok_embed, err_embed, info_embed, COLOUR_INFO
|
||||
from ._base import WormholeBase
|
||||
|
||||
|
||||
class MentionCommands:
|
||||
class MentionCommands(WormholeBase):
|
||||
"""Mixin — mention policy management."""
|
||||
|
||||
@commands.group(name="wh-mention", aliases=["whmention"], invoke_without_command=True)
|
||||
async def wh_mention(self, ctx: commands.Context) -> None:
|
||||
"""Configure mention behaviour."""
|
||||
await ctx.send_help(ctx.command)
|
||||
|
||||
@wh_mention.command(name="set")
|
||||
@WormholeBase.wh_mention.command(name="set")
|
||||
@requires_role(Role.ADMIN)
|
||||
async def wh_mention_set(self, ctx: commands.Context, name: str, kind: str, allowed: bool) -> None:
|
||||
"""Set a mention policy.
|
||||
|
|
@ -38,7 +34,7 @@ class MentionCommands:
|
|||
await ctx.send(embed=ok_embed(f"`{kind}` mentions {'allowed' if allowed else 'blocked'} in `{name}`."))
|
||||
await self._audit(name, f"mention_{kind}", str(ctx.author), details=str(allowed))
|
||||
|
||||
@wh_mention.command(name="exempt")
|
||||
@WormholeBase.wh_mention.command(name="exempt")
|
||||
@requires_role(Role.ADMIN)
|
||||
async def wh_mention_exempt(self, ctx: commands.Context, name: str, user: discord.User) -> None:
|
||||
"""Exempt a user from mention restrictions."""
|
||||
|
|
@ -48,7 +44,7 @@ class MentionCommands:
|
|||
exempt.append(user.id)
|
||||
await ctx.send(embed=ok_embed(f"{user.mention} exempted from mention restrictions in `{name}`."))
|
||||
|
||||
@wh_mention.command(name="unexempt")
|
||||
@WormholeBase.wh_mention.command(name="unexempt")
|
||||
@requires_role(Role.ADMIN)
|
||||
async def wh_mention_unexempt(self, ctx: commands.Context, name: str, user: discord.User) -> None:
|
||||
"""Remove a user's mention exemption."""
|
||||
|
|
@ -58,7 +54,7 @@ class MentionCommands:
|
|||
exempt.remove(user.id)
|
||||
await ctx.send(embed=ok_embed(f"{user.mention} exemption removed in `{name}`."))
|
||||
|
||||
@wh_mention.command(name="optout")
|
||||
@WormholeBase.wh_mention.command(name="optout")
|
||||
async def wh_mention_optout(self, ctx: commands.Context, name: str) -> None:
|
||||
"""Opt out of being pinged via relay."""
|
||||
async with self.config.networks() as ns:
|
||||
|
|
@ -67,7 +63,7 @@ class MentionCommands:
|
|||
optout.append(ctx.author.id)
|
||||
await ctx.send(embed=ok_embed("You've opted out of relay pings."))
|
||||
|
||||
@wh_mention.command(name="optin")
|
||||
@WormholeBase.wh_mention.command(name="optin")
|
||||
async def wh_mention_optin(self, ctx: commands.Context, name: str) -> None:
|
||||
"""Opt back in to relay pings."""
|
||||
async with self.config.networks() as ns:
|
||||
|
|
@ -76,7 +72,7 @@ class MentionCommands:
|
|||
optout.remove(ctx.author.id)
|
||||
await ctx.send(embed=ok_embed("You've opted back in to relay pings."))
|
||||
|
||||
@wh_mention.command(name="serveroverride")
|
||||
@WormholeBase.wh_mention.command(name="serveroverride")
|
||||
@requires_role(Role.ADMIN)
|
||||
async def wh_mention_serveroverride(self, ctx: commands.Context, name: str, guild_id: int, kind: str, allowed: bool) -> None:
|
||||
"""Set per-server mention override."""
|
||||
|
|
@ -94,7 +90,7 @@ class MentionCommands:
|
|||
so.setdefault(gid_str, {})[key_map[kind]] = allowed
|
||||
await ctx.send(embed=ok_embed(f"Server override set for `{guild_id}` in `{name}`."))
|
||||
|
||||
@wh_mention.command(name="show")
|
||||
@WormholeBase.wh_mention.command(name="show")
|
||||
@requires_role(Role.HELPER)
|
||||
async def wh_mention_show(self, ctx: commands.Context, name: str) -> None:
|
||||
"""Show current mention policy."""
|
||||
|
|
|
|||
|
|
@ -10,19 +10,15 @@ from redbot.core import commands
|
|||
|
||||
from ..models.permissions import Role, has_role, requires_role, role_name, get_role
|
||||
from ..utils import ok_embed, err_embed, info_embed, warn_embed, truncate, COLOUR_INFO
|
||||
from ._base import WormholeBase
|
||||
|
||||
|
||||
class ModerationCommands:
|
||||
class ModerationCommands(WormholeBase):
|
||||
"""Mixin — moderation tools (per-network, role-gated)."""
|
||||
|
||||
@commands.group(name="wh-mod", aliases=["whmod"], invoke_without_command=True)
|
||||
async def wh_mod(self, ctx: commands.Context) -> None:
|
||||
"""Network moderation tools."""
|
||||
await ctx.send_help(ctx.command)
|
||||
|
||||
# ── User bans ──────────────────────────────────────────────────────────
|
||||
|
||||
@wh_mod.command(name="ban")
|
||||
@WormholeBase.wh_mod.command(name="ban")
|
||||
@requires_role(Role.MODERATOR)
|
||||
async def wh_mod_ban(self, ctx: commands.Context, name: str, user: discord.User, *, reason: str = "No reason") -> None:
|
||||
"""Ban a user from the network."""
|
||||
|
|
@ -41,7 +37,7 @@ class ModerationCommands:
|
|||
await self._audit(name, "ban", str(ctx.author), str(user), reason)
|
||||
await self._log(nd, warn_embed(f"🔨 **{user}** banned by {ctx.author}\nReason: {reason}"))
|
||||
|
||||
@wh_mod.command(name="unban")
|
||||
@WormholeBase.wh_mod.command(name="unban")
|
||||
@requires_role(Role.MODERATOR)
|
||||
async def wh_mod_unban(self, ctx: commands.Context, name: str, user: discord.User) -> None:
|
||||
"""Unban a user from the network."""
|
||||
|
|
@ -54,7 +50,7 @@ class ModerationCommands:
|
|||
|
||||
# ── User mutes ─────────────────────────────────────────────────────────
|
||||
|
||||
@wh_mod.command(name="mute")
|
||||
@WormholeBase.wh_mod.command(name="mute")
|
||||
@requires_role(Role.MODERATOR)
|
||||
async def wh_mod_mute(self, ctx: commands.Context, name: str, user: discord.User, *, reason: str = "No reason") -> None:
|
||||
"""Mute a user in the network (messages won't relay)."""
|
||||
|
|
@ -71,7 +67,7 @@ class ModerationCommands:
|
|||
await self._audit(name, "mute", str(ctx.author), str(user), reason)
|
||||
await self._log(nd, warn_embed(f"🔇 **{user}** muted by {ctx.author}\nReason: {reason}"))
|
||||
|
||||
@wh_mod.command(name="unmute")
|
||||
@WormholeBase.wh_mod.command(name="unmute")
|
||||
@requires_role(Role.MODERATOR)
|
||||
async def wh_mod_unmute(self, ctx: commands.Context, name: str, user: discord.User) -> None:
|
||||
"""Unmute a user in the network."""
|
||||
|
|
@ -84,7 +80,7 @@ class ModerationCommands:
|
|||
|
||||
# ── Server bans/mutes ──────────────────────────────────────────────────
|
||||
|
||||
@wh_mod.command(name="banserver")
|
||||
@WormholeBase.wh_mod.command(name="banserver")
|
||||
@requires_role(Role.ADMIN)
|
||||
async def wh_mod_banserver(self, ctx: commands.Context, name: str, guild_id: int) -> None:
|
||||
"""Ban a server from the network."""
|
||||
|
|
@ -95,7 +91,7 @@ class ModerationCommands:
|
|||
await ctx.send(embed=ok_embed(f"Server `{guild_id}` banned from `{name}`."))
|
||||
await self._audit(name, "banserver", str(ctx.author), str(guild_id))
|
||||
|
||||
@wh_mod.command(name="unbanserver")
|
||||
@WormholeBase.wh_mod.command(name="unbanserver")
|
||||
@requires_role(Role.ADMIN)
|
||||
async def wh_mod_unbanserver(self, ctx: commands.Context, name: str, guild_id: int) -> None:
|
||||
"""Unban a server from the network."""
|
||||
|
|
@ -106,7 +102,7 @@ class ModerationCommands:
|
|||
await ctx.send(embed=ok_embed(f"Server `{guild_id}` unbanned from `{name}`."))
|
||||
await self._audit(name, "unbanserver", str(ctx.author), str(guild_id))
|
||||
|
||||
@wh_mod.command(name="muteserver")
|
||||
@WormholeBase.wh_mod.command(name="muteserver")
|
||||
@requires_role(Role.ADMIN)
|
||||
async def wh_mod_muteserver(self, ctx: commands.Context, name: str, guild_id: int) -> None:
|
||||
"""Mute a server in the network."""
|
||||
|
|
@ -117,7 +113,7 @@ class ModerationCommands:
|
|||
await ctx.send(embed=ok_embed(f"Server `{guild_id}` muted in `{name}`."))
|
||||
await self._audit(name, "muteserver", str(ctx.author), str(guild_id))
|
||||
|
||||
@wh_mod.command(name="unmuteserver")
|
||||
@WormholeBase.wh_mod.command(name="unmuteserver")
|
||||
@requires_role(Role.ADMIN)
|
||||
async def wh_mod_unmuteserver(self, ctx: commands.Context, name: str, guild_id: int) -> None:
|
||||
"""Unmute a server in the network."""
|
||||
|
|
@ -130,7 +126,7 @@ class ModerationCommands:
|
|||
|
||||
# ── Allowlist ──────────────────────────────────────────────────────────
|
||||
|
||||
@wh_mod.command(name="allowserver")
|
||||
@WormholeBase.wh_mod.command(name="allowserver")
|
||||
@requires_role(Role.ADMIN)
|
||||
async def wh_mod_allowserver(self, ctx: commands.Context, name: str, guild_id: int) -> None:
|
||||
"""Add a server to the allowlist."""
|
||||
|
|
@ -140,7 +136,7 @@ class ModerationCommands:
|
|||
allow.append(guild_id)
|
||||
await ctx.send(embed=ok_embed(f"Server `{guild_id}` added to allowlist for `{name}`."))
|
||||
|
||||
@wh_mod.command(name="removeallow")
|
||||
@WormholeBase.wh_mod.command(name="removeallow")
|
||||
@requires_role(Role.ADMIN)
|
||||
async def wh_mod_removeallow(self, ctx: commands.Context, name: str, guild_id: int) -> None:
|
||||
"""Remove a server from the allowlist."""
|
||||
|
|
@ -152,7 +148,7 @@ class ModerationCommands:
|
|||
|
||||
# ── Purge ──────────────────────────────────────────────────────────────
|
||||
|
||||
@wh_mod.command(name="purge")
|
||||
@WormholeBase.wh_mod.command(name="purge")
|
||||
@requires_role(Role.MODERATOR)
|
||||
async def wh_mod_purge(self, ctx: commands.Context, name: str, count: int = 10) -> None:
|
||||
"""Purge recent relayed messages across all channels (max 50)."""
|
||||
|
|
@ -180,7 +176,7 @@ class ModerationCommands:
|
|||
|
||||
# ── Cross-network mod edit/delete ──────────────────────────────────────
|
||||
|
||||
@wh_mod.command(name="edit")
|
||||
@WormholeBase.wh_mod.command(name="edit")
|
||||
@requires_role(Role.MODERATOR)
|
||||
async def wh_mod_edit(self, ctx: commands.Context, name: str, message_id: int, *, new_content: str) -> None:
|
||||
"""Edit a relayed message across all channels."""
|
||||
|
|
@ -209,7 +205,7 @@ class ModerationCommands:
|
|||
await ctx.send(embed=ok_embed(f"Edited {edited} relayed copies."))
|
||||
await self._audit(name, "mod_edit", str(ctx.author), str(orig_id), truncate(new_content, 100))
|
||||
|
||||
@wh_mod.command(name="nuke")
|
||||
@WormholeBase.wh_mod.command(name="nuke")
|
||||
@requires_role(Role.MODERATOR)
|
||||
async def wh_mod_nuke(self, ctx: commands.Context, name: str, message_id: int) -> None:
|
||||
"""Delete a message and all its relayed copies across the network."""
|
||||
|
|
@ -243,7 +239,7 @@ class ModerationCommands:
|
|||
|
||||
# ── Audit log ──────────────────────────────────────────────────────────
|
||||
|
||||
@wh_mod.command(name="audit")
|
||||
@WormholeBase.wh_mod.command(name="audit")
|
||||
@requires_role(Role.HELPER)
|
||||
async def wh_mod_audit(self, ctx: commands.Context, name: str, count: int = 20) -> None:
|
||||
"""View the network audit log."""
|
||||
|
|
@ -275,7 +271,7 @@ class ModerationCommands:
|
|||
|
||||
# ── Ban/mute lists ─────────────────────────────────────────────────────
|
||||
|
||||
@wh_mod.command(name="bans")
|
||||
@WormholeBase.wh_mod.command(name="bans")
|
||||
@requires_role(Role.HELPER)
|
||||
async def wh_mod_bans(self, ctx: commands.Context, name: str) -> None:
|
||||
"""List banned users."""
|
||||
|
|
@ -291,7 +287,7 @@ class ModerationCommands:
|
|||
lines.append(f"• {user or uid}")
|
||||
await ctx.send(embed=info_embed("\n".join(lines), title=f"🔨 Banned Users — {name}"))
|
||||
|
||||
@wh_mod.command(name="mutes")
|
||||
@WormholeBase.wh_mod.command(name="mutes")
|
||||
@requires_role(Role.HELPER)
|
||||
async def wh_mod_mutes(self, ctx: commands.Context, name: str) -> None:
|
||||
"""List muted users."""
|
||||
|
|
|
|||
|
|
@ -12,12 +12,13 @@ from redbot.core import commands
|
|||
from ..models.config import DEFAULT_NETWORK
|
||||
from ..models.permissions import Role, has_role, requires_role, role_name, get_role, list_staff
|
||||
from ..utils import ok_embed, err_embed, info_embed, warn_embed, COLOUR_INFO, COLOUR_OK, truncate
|
||||
from ._base import WormholeBase
|
||||
|
||||
|
||||
class NetworkCommands:
|
||||
class NetworkCommands(WormholeBase):
|
||||
"""Mixin — network lifecycle commands."""
|
||||
|
||||
@commands.hybrid_command(name="wh-create")
|
||||
@WormholeBase.wh.command(name="create")
|
||||
async def wh_create(self, ctx: commands.Context, name: str, *, description: str = "") -> None:
|
||||
"""Create a new wormhole network."""
|
||||
nets = await self.config.networks()
|
||||
|
|
@ -40,7 +41,7 @@ class NetworkCommands:
|
|||
))
|
||||
await self._audit(name, "create", str(ctx.author))
|
||||
|
||||
@commands.hybrid_command(name="wh-delete")
|
||||
@WormholeBase.wh.command(name="delete")
|
||||
async def wh_delete(self, ctx: commands.Context, name: str) -> None:
|
||||
"""Delete a network (owner or bot owner only)."""
|
||||
nd = await self._net(name)
|
||||
|
|
@ -54,7 +55,7 @@ class NetworkCommands:
|
|||
self.cooldowns.pop(name, None)
|
||||
await ctx.send(embed=ok_embed(f"Network `{name}` deleted."))
|
||||
|
||||
@commands.hybrid_command(name="wh-open")
|
||||
@WormholeBase.wh.command(name="open")
|
||||
@requires_role(Role.ADMIN)
|
||||
async def wh_open(self, ctx: commands.Context, name: str) -> None:
|
||||
"""Add the current channel to a network."""
|
||||
|
|
@ -63,7 +64,6 @@ class NetworkCommands:
|
|||
return await ctx.send(embed=err_embed(f"Network `{name}` not found."))
|
||||
if ctx.channel.id in nd.get("channels", []):
|
||||
return await ctx.send(embed=err_embed("This channel is already in the network."))
|
||||
# Check not in another network
|
||||
existing = await self._net_for_ch(ctx.channel.id)
|
||||
if existing:
|
||||
return await ctx.send(embed=err_embed(f"This channel is already in network `{existing}`."))
|
||||
|
|
@ -72,7 +72,7 @@ class NetworkCommands:
|
|||
await ctx.send(embed=ok_embed(f"Channel linked to `{name}`. Messages will now relay."))
|
||||
await self._audit(name, "open", str(ctx.author), str(ctx.channel.id))
|
||||
|
||||
@commands.hybrid_command(name="wh-close")
|
||||
@WormholeBase.wh.command(name="close")
|
||||
async def wh_close(self, ctx: commands.Context, name: str = None) -> None:
|
||||
"""Remove the current channel from a network."""
|
||||
if not name:
|
||||
|
|
@ -91,7 +91,7 @@ class NetworkCommands:
|
|||
await ctx.send(embed=ok_embed(f"Channel removed from `{name}`."))
|
||||
await self._audit(name, "close", str(ctx.author), str(ctx.channel.id))
|
||||
|
||||
@commands.hybrid_command(name="wh-list")
|
||||
@WormholeBase.wh.command(name="list")
|
||||
async def wh_list(self, ctx: commands.Context) -> None:
|
||||
"""List all networks you have access to."""
|
||||
nets = await self.config.networks()
|
||||
|
|
@ -107,7 +107,7 @@ class NetworkCommands:
|
|||
em = discord.Embed(title="🌀 Wormhole Networks", description="\n".join(lines), colour=COLOUR_INFO)
|
||||
await ctx.send(embed=em)
|
||||
|
||||
@commands.hybrid_command(name="wh-discover")
|
||||
@WormholeBase.wh.command(name="discover")
|
||||
async def wh_discover(self, ctx: commands.Context) -> None:
|
||||
"""Browse public networks."""
|
||||
nets = await self.config.networks()
|
||||
|
|
@ -122,7 +122,7 @@ class NetworkCommands:
|
|||
em = discord.Embed(title="🔍 Public Networks", description="\n".join(lines), colour=COLOUR_INFO)
|
||||
await ctx.send(embed=em)
|
||||
|
||||
@commands.hybrid_command(name="wh-info")
|
||||
@WormholeBase.wh.command(name="info")
|
||||
async def wh_info(self, ctx: commands.Context, name: str) -> None:
|
||||
"""Show detailed info about a network."""
|
||||
nd = await self._net(name)
|
||||
|
|
@ -137,7 +137,6 @@ class NetworkCommands:
|
|||
em.add_field(name="Status", value=status, inline=True)
|
||||
em.add_field(name="Owner", value=str(owner or nd["owner_id"]), inline=True)
|
||||
|
||||
# Staff count by role
|
||||
staff = list_staff(nd)
|
||||
staff_summary = []
|
||||
for role in (Role.ADMIN, Role.MODERATOR, Role.HELPER):
|
||||
|
|
|
|||
|
|
@ -9,17 +9,13 @@ from redbot.core import commands
|
|||
|
||||
from ..models.permissions import Role, requires_role, has_role
|
||||
from ..utils import ok_embed, err_embed, info_embed, warn_embed, truncate, COLOUR_INFO
|
||||
from ._base import WormholeBase
|
||||
|
||||
|
||||
class ReportCommands:
|
||||
class ReportCommands(WormholeBase):
|
||||
"""Mixin — user report system (per-network)."""
|
||||
|
||||
@commands.group(name="wh-report", aliases=["whreport"], invoke_without_command=True)
|
||||
async def wh_report(self, ctx: commands.Context) -> None:
|
||||
"""Network report system."""
|
||||
await ctx.send_help(ctx.command)
|
||||
|
||||
@wh_report.command(name="msg")
|
||||
@WormholeBase.wh_report.command(name="msg")
|
||||
async def wh_report_msg(self, ctx: commands.Context, message_id: int, *, reason: str = "No reason provided") -> None:
|
||||
"""Report a message by ID."""
|
||||
net_name = await self._net_for_ch(ctx.channel.id)
|
||||
|
|
@ -51,7 +47,7 @@ class ReportCommands:
|
|||
title="New Report",
|
||||
))
|
||||
|
||||
@wh_report.command(name="list")
|
||||
@WormholeBase.wh_report.command(name="list")
|
||||
@requires_role(Role.HELPER)
|
||||
async def wh_report_list(self, ctx: commands.Context, name: str, show_resolved: bool = False) -> None:
|
||||
"""List reports for a network."""
|
||||
|
|
@ -74,7 +70,7 @@ class ReportCommands:
|
|||
em = discord.Embed(title=f"🚩 Reports — {name}", description="\n".join(lines), colour=COLOUR_INFO)
|
||||
await ctx.send(embed=em)
|
||||
|
||||
@wh_report.command(name="view")
|
||||
@WormholeBase.wh_report.command(name="view")
|
||||
@requires_role(Role.HELPER)
|
||||
async def wh_report_view(self, ctx: commands.Context, name: str, report_id: int) -> None:
|
||||
"""View details of a specific report."""
|
||||
|
|
@ -103,7 +99,7 @@ class ReportCommands:
|
|||
em.add_field(name="Resolution", value=report["resolution"], inline=False)
|
||||
await ctx.send(embed=em)
|
||||
|
||||
@wh_report.command(name="resolve")
|
||||
@WormholeBase.wh_report.command(name="resolve")
|
||||
@requires_role(Role.MODERATOR)
|
||||
async def wh_report_resolve(self, ctx: commands.Context, name: str, report_id: int, *, resolution: str = "Resolved") -> None:
|
||||
"""Resolve a report."""
|
||||
|
|
@ -120,7 +116,7 @@ class ReportCommands:
|
|||
await ctx.send(embed=ok_embed(f"Report #{report_id} resolved."))
|
||||
await self._audit(name, "report_resolve", str(ctx.author), str(report_id), resolution)
|
||||
|
||||
@wh_report.command(name="dismiss")
|
||||
@WormholeBase.wh_report.command(name="dismiss")
|
||||
@requires_role(Role.MODERATOR)
|
||||
async def wh_report_dismiss(self, ctx: commands.Context, name: str, report_id: int, *, reason: str = "Dismissed") -> None:
|
||||
"""Dismiss a report."""
|
||||
|
|
|
|||
|
|
@ -9,19 +9,15 @@ from redbot.core import commands
|
|||
|
||||
from ..models.permissions import Role, requires_role
|
||||
from ..utils import ok_embed, err_embed, info_embed, COLOUR_INFO, COLOUR_OK
|
||||
from ._base import WormholeBase
|
||||
|
||||
|
||||
class SettingsCommands:
|
||||
class SettingsCommands(WormholeBase):
|
||||
"""Mixin — network settings management."""
|
||||
|
||||
@commands.group(name="wh-set", aliases=["whset"], invoke_without_command=True)
|
||||
async def wh_set(self, ctx: commands.Context) -> None:
|
||||
"""Configure network settings."""
|
||||
await ctx.send_help(ctx.command)
|
||||
|
||||
# ── Relay mode ─────────────────────────────────────────────────────────
|
||||
|
||||
@wh_set.command(name="relaymode")
|
||||
@WormholeBase.wh_set.command(name="relaymode")
|
||||
@requires_role(Role.ADMIN)
|
||||
async def wh_set_relaymode(self, ctx: commands.Context, name: str, mode: str) -> None:
|
||||
"""Set relay mode: ``webhook``, ``embed``, or ``compact``."""
|
||||
|
|
@ -34,7 +30,7 @@ class SettingsCommands:
|
|||
|
||||
# ── Webhooks ───────────────────────────────────────────────────────────
|
||||
|
||||
@wh_set.command(name="webhooks")
|
||||
@WormholeBase.wh_set.command(name="webhooks")
|
||||
@requires_role(Role.ADMIN)
|
||||
async def wh_set_webhooks(self, ctx: commands.Context, name: str, enabled: bool) -> None:
|
||||
"""Enable or disable webhook relay."""
|
||||
|
|
@ -45,7 +41,7 @@ class SettingsCommands:
|
|||
|
||||
# ── Sync toggles ──────────────────────────────────────────────────────
|
||||
|
||||
@wh_set.command(name="sync")
|
||||
@WormholeBase.wh_set.command(name="sync")
|
||||
@requires_role(Role.ADMIN)
|
||||
async def wh_set_sync(self, ctx: commands.Context, name: str, feature: str, enabled: bool) -> None:
|
||||
"""Toggle sync features: ``edits``, ``deletes``, ``reactions``, ``replies``, ``stickers``, ``pins``, ``threads``, ``typing``."""
|
||||
|
|
@ -64,7 +60,7 @@ class SettingsCommands:
|
|||
|
||||
# ── Identity ───────────────────────────────────────────────────────────
|
||||
|
||||
@wh_set.command(name="imagemode")
|
||||
@WormholeBase.wh_set.command(name="imagemode")
|
||||
@requires_role(Role.ADMIN)
|
||||
async def wh_set_imagemode(self, ctx: commands.Context, name: str, mode: str) -> None:
|
||||
"""Set avatar mode: ``user``, ``server``, ``custom``."""
|
||||
|
|
@ -74,7 +70,7 @@ class SettingsCommands:
|
|||
ns[name]["image_mode"] = mode
|
||||
await ctx.send(embed=ok_embed(f"Image mode for `{name}` set to **{mode}**."))
|
||||
|
||||
@wh_set.command(name="namemode")
|
||||
@WormholeBase.wh_set.command(name="namemode")
|
||||
@requires_role(Role.ADMIN)
|
||||
async def wh_set_namemode(self, ctx: commands.Context, name: str, mode: str) -> None:
|
||||
"""Set name mode: ``user``, ``server``, ``both``, ``custom``."""
|
||||
|
|
@ -84,7 +80,7 @@ class SettingsCommands:
|
|||
ns[name]["name_mode"] = mode
|
||||
await ctx.send(embed=ok_embed(f"Name mode for `{name}` set to **{mode}**."))
|
||||
|
||||
@wh_set.command(name="icon")
|
||||
@WormholeBase.wh_set.command(name="icon")
|
||||
@requires_role(Role.ADMIN)
|
||||
async def wh_set_icon(self, ctx: commands.Context, name: str, url: str = None) -> None:
|
||||
"""Set a custom network icon URL."""
|
||||
|
|
@ -92,7 +88,7 @@ class SettingsCommands:
|
|||
ns[name]["custom_icon"] = url
|
||||
await ctx.send(embed=ok_embed(f"Custom icon {'set' if url else 'cleared'} for `{name}`."))
|
||||
|
||||
@wh_set.command(name="customname")
|
||||
@WormholeBase.wh_set.command(name="customname")
|
||||
@requires_role(Role.ADMIN)
|
||||
async def wh_set_customname(self, ctx: commands.Context, name: str, *, value: str = None) -> None:
|
||||
"""Set a custom display name for relayed messages."""
|
||||
|
|
@ -100,7 +96,7 @@ class SettingsCommands:
|
|||
ns[name]["custom_name"] = value
|
||||
await ctx.send(embed=ok_embed(f"Custom name {'set' if value else 'cleared'} for `{name}`."))
|
||||
|
||||
@wh_set.command(name="colour", aliases=["color"])
|
||||
@WormholeBase.wh_set.command(name="colour", aliases=["color"])
|
||||
@requires_role(Role.ADMIN)
|
||||
async def wh_set_colour(self, ctx: commands.Context, name: str, hex_code: str = None) -> None:
|
||||
"""Set the network embed colour (hex, e.g. ``#ff5733``)."""
|
||||
|
|
@ -117,7 +113,7 @@ class SettingsCommands:
|
|||
|
||||
# ── Description / MOTD / rules ─────────────────────────────────────────
|
||||
|
||||
@wh_set.command(name="description", aliases=["desc"])
|
||||
@WormholeBase.wh_set.command(name="description", aliases=["desc"])
|
||||
@requires_role(Role.ADMIN)
|
||||
async def wh_set_desc(self, ctx: commands.Context, name: str, *, text: str) -> None:
|
||||
"""Set the network description."""
|
||||
|
|
@ -125,7 +121,7 @@ class SettingsCommands:
|
|||
ns[name]["description"] = text
|
||||
await ctx.send(embed=ok_embed(f"Description updated for `{name}`."))
|
||||
|
||||
@wh_set.command(name="motd")
|
||||
@WormholeBase.wh_set.command(name="motd")
|
||||
@requires_role(Role.ADMIN)
|
||||
async def wh_set_motd(self, ctx: commands.Context, name: str, *, text: str = "") -> None:
|
||||
"""Set or clear the Message of the Day."""
|
||||
|
|
@ -133,7 +129,7 @@ class SettingsCommands:
|
|||
ns[name]["motd"] = text
|
||||
await ctx.send(embed=ok_embed(f"MOTD {'set' if text else 'cleared'} for `{name}`."))
|
||||
|
||||
@wh_set.command(name="welcome")
|
||||
@WormholeBase.wh_set.command(name="welcome")
|
||||
@requires_role(Role.ADMIN)
|
||||
async def wh_set_welcome(self, ctx: commands.Context, name: str, *, text: str = "") -> None:
|
||||
"""Set or clear the welcome message for new servers."""
|
||||
|
|
@ -143,7 +139,7 @@ class SettingsCommands:
|
|||
|
||||
# ── Network behaviour ──────────────────────────────────────────────────
|
||||
|
||||
@wh_set.command(name="freeze")
|
||||
@WormholeBase.wh_set.command(name="freeze")
|
||||
@requires_role(Role.ADMIN)
|
||||
async def wh_set_freeze(self, ctx: commands.Context, name: str) -> None:
|
||||
"""Freeze the network — relay paused."""
|
||||
|
|
@ -152,7 +148,7 @@ class SettingsCommands:
|
|||
await ctx.send(embed=ok_embed(f"`{name}` is now ❄️ frozen. Messages won't relay."))
|
||||
await self._audit(name, "freeze", str(ctx.author))
|
||||
|
||||
@wh_set.command(name="unfreeze")
|
||||
@WormholeBase.wh_set.command(name="unfreeze")
|
||||
@requires_role(Role.ADMIN)
|
||||
async def wh_set_unfreeze(self, ctx: commands.Context, name: str) -> None:
|
||||
"""Unfreeze the network — resume relay."""
|
||||
|
|
@ -161,7 +157,7 @@ class SettingsCommands:
|
|||
await ctx.send(embed=ok_embed(f"`{name}` is now 🟢 active."))
|
||||
await self._audit(name, "unfreeze", str(ctx.author))
|
||||
|
||||
@wh_set.command(name="anonymous", aliases=["anon"])
|
||||
@WormholeBase.wh_set.command(name="anonymous", aliases=["anon"])
|
||||
@requires_role(Role.ADMIN)
|
||||
async def wh_set_anonymous(self, ctx: commands.Context, name: str, enabled: bool) -> None:
|
||||
"""Toggle anonymous mode."""
|
||||
|
|
@ -172,7 +168,7 @@ class SettingsCommands:
|
|||
ns[name]["anon_salt"] = secrets.token_hex(8)
|
||||
await ctx.send(embed=ok_embed(f"Anonymous mode {'enabled' if enabled else 'disabled'} for `{name}`."))
|
||||
|
||||
@wh_set.command(name="nsfw")
|
||||
@WormholeBase.wh_set.command(name="nsfw")
|
||||
@requires_role(Role.ADMIN)
|
||||
async def wh_set_nsfw(self, ctx: commands.Context, name: str, gate: bool) -> None:
|
||||
"""Toggle NSFW gate (only relay to NSFW channels if source is NSFW)."""
|
||||
|
|
@ -180,7 +176,7 @@ class SettingsCommands:
|
|||
ns[name]["nsfw_gate"] = gate
|
||||
await ctx.send(embed=ok_embed(f"NSFW gate {'enabled' if gate else 'disabled'} for `{name}`."))
|
||||
|
||||
@wh_set.command(name="mediaonly")
|
||||
@WormholeBase.wh_set.command(name="mediaonly")
|
||||
@requires_role(Role.ADMIN)
|
||||
async def wh_set_mediaonly(self, ctx: commands.Context, name: str, enabled: bool) -> None:
|
||||
"""Toggle media-only mode (only relay messages with attachments)."""
|
||||
|
|
@ -188,7 +184,7 @@ class SettingsCommands:
|
|||
ns[name]["media_only"] = enabled
|
||||
await ctx.send(embed=ok_embed(f"Media-only mode {'enabled' if enabled else 'disabled'} for `{name}`."))
|
||||
|
||||
@wh_set.command(name="silent")
|
||||
@WormholeBase.wh_set.command(name="silent")
|
||||
@requires_role(Role.ADMIN)
|
||||
async def wh_set_silent(self, ctx: commands.Context, name: str, enabled: bool) -> None:
|
||||
"""Toggle silent mode (suppress status messages)."""
|
||||
|
|
@ -196,7 +192,7 @@ class SettingsCommands:
|
|||
ns[name]["silent"] = enabled
|
||||
await ctx.send(embed=ok_embed(f"Silent mode {'enabled' if enabled else 'disabled'} for `{name}`."))
|
||||
|
||||
@wh_set.command(name="embeds")
|
||||
@WormholeBase.wh_set.command(name="embeds")
|
||||
@requires_role(Role.ADMIN)
|
||||
async def wh_set_embeds(self, ctx: commands.Context, name: str, enabled: bool) -> None:
|
||||
"""Toggle forwarding embeds from relayed messages."""
|
||||
|
|
@ -206,7 +202,7 @@ class SettingsCommands:
|
|||
|
||||
# ── Rate limiting ──────────────────────────────────────────────────────
|
||||
|
||||
@wh_set.command(name="ratelimit")
|
||||
@WormholeBase.wh_set.command(name="ratelimit")
|
||||
@requires_role(Role.ADMIN)
|
||||
async def wh_set_ratelimit(self, ctx: commands.Context, name: str, rate: int = 5, per: float = 10.0) -> None:
|
||||
"""Set rate limit: *rate* messages per *per* seconds."""
|
||||
|
|
@ -220,7 +216,7 @@ class SettingsCommands:
|
|||
self.cooldowns[name] = CooldownBucket(rate, per)
|
||||
await ctx.send(embed=ok_embed(f"Rate limit: {rate} msgs per {per}s for `{name}`."))
|
||||
|
||||
@wh_set.command(name="slowmode")
|
||||
@WormholeBase.wh_set.command(name="slowmode")
|
||||
@requires_role(Role.ADMIN)
|
||||
async def wh_set_slowmode(self, ctx: commands.Context, name: str, seconds: int = 0) -> None:
|
||||
"""Set slowmode (seconds between messages per user, 0 to disable)."""
|
||||
|
|
@ -230,7 +226,7 @@ class SettingsCommands:
|
|||
|
||||
# ── Log channel ────────────────────────────────────────────────────────
|
||||
|
||||
@wh_set.command(name="logchannel", aliases=["log"])
|
||||
@WormholeBase.wh_set.command(name="logchannel", aliases=["log"])
|
||||
@requires_role(Role.ADMIN)
|
||||
async def wh_set_logchannel(self, ctx: commands.Context, name: str, channel: discord.TextChannel = None) -> None:
|
||||
"""Set (or clear) the mod log channel."""
|
||||
|
|
@ -240,7 +236,7 @@ class SettingsCommands:
|
|||
|
||||
# ── Server nicknames ───────────────────────────────────────────────────
|
||||
|
||||
@wh_set.command(name="servernick")
|
||||
@WormholeBase.wh_set.command(name="servernick")
|
||||
@requires_role(Role.ADMIN)
|
||||
async def wh_set_servernick(self, ctx: commands.Context, name: str, guild_id: int, *, nick: str = None) -> None:
|
||||
"""Set or clear a nickname for a server in relay messages."""
|
||||
|
|
@ -254,7 +250,7 @@ class SettingsCommands:
|
|||
|
||||
# ── Relay delay ────────────────────────────────────────────────────────
|
||||
|
||||
@wh_set.command(name="delay")
|
||||
@WormholeBase.wh_set.command(name="delay")
|
||||
@requires_role(Role.ADMIN)
|
||||
async def wh_set_delay(self, ctx: commands.Context, name: str, seconds: int = 0) -> None:
|
||||
"""Set relay delay (seconds before messages are relayed, 0 to disable)."""
|
||||
|
|
@ -264,7 +260,7 @@ class SettingsCommands:
|
|||
|
||||
# ── Ephemeral auto-delete ──────────────────────────────────────────────
|
||||
|
||||
@wh_set.command(name="ephemeral")
|
||||
@WormholeBase.wh_set.command(name="ephemeral")
|
||||
@requires_role(Role.ADMIN)
|
||||
async def wh_set_ephemeral(self, ctx: commands.Context, name: str, seconds: int = 0) -> None:
|
||||
"""Auto-delete relayed messages after N seconds (0 to disable)."""
|
||||
|
|
@ -274,7 +270,7 @@ class SettingsCommands:
|
|||
|
||||
# ── Discovery ──────────────────────────────────────────────────────────
|
||||
|
||||
@wh_set.command(name="public")
|
||||
@WormholeBase.wh_set.command(name="public")
|
||||
@requires_role(Role.OWNER)
|
||||
async def wh_set_public(self, ctx: commands.Context, name: str, enabled: bool) -> None:
|
||||
"""Make network publicly discoverable."""
|
||||
|
|
@ -282,7 +278,7 @@ class SettingsCommands:
|
|||
ns[name]["public"] = enabled
|
||||
await ctx.send(embed=ok_embed(f"`{name}` is now {'public' if enabled else 'private'}."))
|
||||
|
||||
@wh_set.command(name="tags")
|
||||
@WormholeBase.wh_set.command(name="tags")
|
||||
@requires_role(Role.ADMIN)
|
||||
async def wh_set_tags(self, ctx: commands.Context, name: str, *, tags: str) -> None:
|
||||
"""Set discovery tags (comma-separated)."""
|
||||
|
|
@ -293,7 +289,7 @@ class SettingsCommands:
|
|||
|
||||
# ── Channel overrides ──────────────────────────────────────────────────
|
||||
|
||||
@wh_set.command(name="override")
|
||||
@WormholeBase.wh_set.command(name="override")
|
||||
@requires_role(Role.ADMIN)
|
||||
async def wh_set_override(self, ctx: commands.Context, name: str, key: str, value: str) -> None:
|
||||
"""Set a per-channel config override for the current channel."""
|
||||
|
|
@ -321,7 +317,7 @@ class SettingsCommands:
|
|||
|
||||
# ── View all settings ──────────────────────────────────────────────────
|
||||
|
||||
@wh_set.command(name="show")
|
||||
@WormholeBase.wh_set.command(name="show")
|
||||
@requires_role(Role.HELPER)
|
||||
async def wh_set_show(self, ctx: commands.Context, name: str) -> None:
|
||||
"""Show current settings for a network."""
|
||||
|
|
|
|||
|
|
@ -10,14 +10,15 @@ from redbot.core import commands
|
|||
|
||||
from ..models.permissions import Role, has_role, requires_role, get_role, role_name
|
||||
from ..utils import ok_embed, err_embed, info_embed, star_embed, warn_embed, truncate, COLOUR_INFO, COLOUR_STAR
|
||||
from ._base import WormholeBase
|
||||
|
||||
|
||||
class SocialCommands:
|
||||
class SocialCommands(WormholeBase):
|
||||
"""Mixin — social features."""
|
||||
|
||||
# ── Profiles ───────────────────────────────────────────────────────────
|
||||
|
||||
@commands.hybrid_command(name="wh-profile")
|
||||
@WormholeBase.wh.command(name="profile")
|
||||
async def wh_profile(self, ctx: commands.Context, name: str, user: discord.User = None) -> None:
|
||||
"""View a user's wormhole profile in a network."""
|
||||
nd = await self._net(name)
|
||||
|
|
@ -46,12 +47,7 @@ class SocialCommands:
|
|||
|
||||
# ── Karma ──────────────────────────────────────────────────────────────
|
||||
|
||||
@commands.group(name="wh-karma", aliases=["whkarma"], invoke_without_command=True)
|
||||
async def wh_karma(self, ctx: commands.Context) -> None:
|
||||
"""Karma system commands."""
|
||||
await ctx.send_help(ctx.command)
|
||||
|
||||
@wh_karma.command(name="enable")
|
||||
@WormholeBase.wh_karma.command(name="enable")
|
||||
@requires_role(Role.ADMIN)
|
||||
async def wh_karma_enable(self, ctx: commands.Context, name: str, enabled: bool = True) -> None:
|
||||
"""Enable or disable the karma system."""
|
||||
|
|
@ -59,7 +55,7 @@ class SocialCommands:
|
|||
ns[name]["karma_enabled"] = enabled
|
||||
await ctx.send(embed=ok_embed(f"Karma {'enabled' if enabled else 'disabled'} for `{name}`."))
|
||||
|
||||
@wh_karma.command(name="emoji")
|
||||
@WormholeBase.wh_karma.command(name="emoji")
|
||||
@requires_role(Role.ADMIN)
|
||||
async def wh_karma_emoji(self, ctx: commands.Context, name: str, emoji: str = "👍") -> None:
|
||||
"""Set the karma reaction emoji."""
|
||||
|
|
@ -67,7 +63,7 @@ class SocialCommands:
|
|||
ns[name]["karma_emoji"] = emoji
|
||||
await ctx.send(embed=ok_embed(f"Karma emoji set to {emoji} for `{name}`."))
|
||||
|
||||
@wh_karma.command(name="top")
|
||||
@WormholeBase.wh_karma.command(name="top")
|
||||
async def wh_karma_top(self, ctx: commands.Context, name: str, count: int = 10) -> None:
|
||||
"""Show karma leaderboard."""
|
||||
nd = await self._net(name)
|
||||
|
|
@ -88,12 +84,7 @@ class SocialCommands:
|
|||
|
||||
# ── Starboard ──────────────────────────────────────────────────────────
|
||||
|
||||
@commands.group(name="wh-star", aliases=["whstar"], invoke_without_command=True)
|
||||
async def wh_star(self, ctx: commands.Context) -> None:
|
||||
"""Starboard commands."""
|
||||
await ctx.send_help(ctx.command)
|
||||
|
||||
@wh_star.command(name="enable")
|
||||
@WormholeBase.wh_star.command(name="enable")
|
||||
@requires_role(Role.ADMIN)
|
||||
async def wh_star_enable(self, ctx: commands.Context, name: str, enabled: bool = True) -> None:
|
||||
"""Enable or disable starboard."""
|
||||
|
|
@ -101,7 +92,7 @@ class SocialCommands:
|
|||
ns[name]["starboard_enabled"] = enabled
|
||||
await ctx.send(embed=ok_embed(f"Starboard {'enabled' if enabled else 'disabled'} for `{name}`."))
|
||||
|
||||
@wh_star.command(name="channel")
|
||||
@WormholeBase.wh_star.command(name="channel")
|
||||
@requires_role(Role.ADMIN)
|
||||
async def wh_star_channel(self, ctx: commands.Context, name: str, channel: discord.TextChannel = None) -> None:
|
||||
"""Set the starboard channel."""
|
||||
|
|
@ -109,7 +100,7 @@ class SocialCommands:
|
|||
ns[name]["starboard_channel"] = channel.id if channel else None
|
||||
await ctx.send(embed=ok_embed(f"Starboard channel {'set' if channel else 'cleared'} for `{name}`."))
|
||||
|
||||
@wh_star.command(name="threshold")
|
||||
@WormholeBase.wh_star.command(name="threshold")
|
||||
@requires_role(Role.ADMIN)
|
||||
async def wh_star_threshold(self, ctx: commands.Context, name: str, threshold: int = 3) -> None:
|
||||
"""Set minimum stars to reach the starboard."""
|
||||
|
|
@ -119,12 +110,7 @@ class SocialCommands:
|
|||
|
||||
# ── Highlights ─────────────────────────────────────────────────────────
|
||||
|
||||
@commands.group(name="wh-hl", aliases=["whhl"], invoke_without_command=True)
|
||||
async def wh_hl(self, ctx: commands.Context) -> None:
|
||||
"""Keyword highlight notifications."""
|
||||
await ctx.send_help(ctx.command)
|
||||
|
||||
@wh_hl.command(name="add")
|
||||
@WormholeBase.wh_hl.command(name="add")
|
||||
async def wh_hl_add(self, ctx: commands.Context, name: str, *, keyword: str) -> None:
|
||||
"""Add a keyword to highlight."""
|
||||
async with self.config.networks() as ns:
|
||||
|
|
@ -138,7 +124,7 @@ class SocialCommands:
|
|||
user_hl.append(keyword)
|
||||
await ctx.send(embed=ok_embed(f"Highlight `{keyword}` added for `{name}`."))
|
||||
|
||||
@wh_hl.command(name="remove", aliases=["rm"])
|
||||
@WormholeBase.wh_hl.command(name="remove", aliases=["rm"])
|
||||
async def wh_hl_remove(self, ctx: commands.Context, name: str, *, keyword: str) -> None:
|
||||
"""Remove a highlight keyword."""
|
||||
async with self.config.networks() as ns:
|
||||
|
|
@ -147,7 +133,7 @@ class SocialCommands:
|
|||
ns[name]["highlights"][str(ctx.author.id)] = [k for k in user_hl if k.lower() != keyword.lower()]
|
||||
await ctx.send(embed=ok_embed(f"Highlight `{keyword}` removed."))
|
||||
|
||||
@wh_hl.command(name="list")
|
||||
@WormholeBase.wh_hl.command(name="list")
|
||||
async def wh_hl_list(self, ctx: commands.Context, name: str) -> None:
|
||||
"""List your highlights."""
|
||||
nd = await self._net(name)
|
||||
|
|
@ -160,12 +146,7 @@ class SocialCommands:
|
|||
|
||||
# ── Bookmarks ──────────────────────────────────────────────────────────
|
||||
|
||||
@commands.group(name="wh-bm", aliases=["whbm"], invoke_without_command=True)
|
||||
async def wh_bm(self, ctx: commands.Context) -> None:
|
||||
"""Message bookmarks."""
|
||||
await ctx.send_help(ctx.command)
|
||||
|
||||
@wh_bm.command(name="list")
|
||||
@WormholeBase.wh_bm.command(name="list")
|
||||
async def wh_bm_list(self, ctx: commands.Context) -> None:
|
||||
"""List your bookmarks."""
|
||||
bm = await self.config.bookmarks()
|
||||
|
|
@ -181,7 +162,7 @@ class SocialCommands:
|
|||
em = discord.Embed(title="📌 Bookmarks", description="\n".join(lines), colour=COLOUR_INFO)
|
||||
await ctx.send(embed=em)
|
||||
|
||||
@wh_bm.command(name="clear")
|
||||
@WormholeBase.wh_bm.command(name="clear")
|
||||
async def wh_bm_clear(self, ctx: commands.Context) -> None:
|
||||
"""Clear all your bookmarks."""
|
||||
async with self.config.bookmarks() as bm:
|
||||
|
|
|
|||
|
|
@ -18,17 +18,13 @@ from ..models.permissions import (
|
|||
remove_staff,
|
||||
)
|
||||
from ..utils import ok_embed, err_embed, info_embed, COLOUR_INFO
|
||||
from ._base import WormholeBase
|
||||
|
||||
|
||||
class StaffCommands:
|
||||
class StaffCommands(WormholeBase):
|
||||
"""Mixin — staff management (per-network hierarchy)."""
|
||||
|
||||
@commands.group(name="wh-staff", aliases=["whstaff"], invoke_without_command=True)
|
||||
async def wh_staff(self, ctx: commands.Context) -> None:
|
||||
"""Manage network staff — add, remove, list, promote, demote."""
|
||||
await ctx.send_help(ctx.command)
|
||||
|
||||
@wh_staff.command(name="add")
|
||||
@WormholeBase.wh_staff.command(name="add")
|
||||
async def wh_staff_add(self, ctx: commands.Context, name: str, user: discord.User, role_str: str = "moderator") -> None:
|
||||
"""Assign a staff role to a user.
|
||||
|
||||
|
|
@ -57,7 +53,7 @@ class StaffCommands:
|
|||
))
|
||||
await self._audit(name, "staff_add", str(ctx.author), str(user), f"role={role_name(target_role)}")
|
||||
|
||||
@wh_staff.command(name="remove", aliases=["rm"])
|
||||
@WormholeBase.wh_staff.command(name="remove", aliases=["rm"])
|
||||
async def wh_staff_rm(self, ctx: commands.Context, name: str, user: discord.User) -> None:
|
||||
"""Remove a user from network staff."""
|
||||
nd = await self._net(name)
|
||||
|
|
@ -81,7 +77,7 @@ class StaffCommands:
|
|||
await ctx.send(embed=ok_embed(f"{user.mention} removed from staff in `{name}`."))
|
||||
await self._audit(name, "staff_rm", str(ctx.author), str(user))
|
||||
|
||||
@wh_staff.command(name="promote")
|
||||
@WormholeBase.wh_staff.command(name="promote")
|
||||
async def wh_staff_promote(self, ctx: commands.Context, name: str, user: discord.User) -> None:
|
||||
"""Promote a staff member one tier up."""
|
||||
nd = await self._net(name)
|
||||
|
|
@ -110,7 +106,7 @@ class StaffCommands:
|
|||
))
|
||||
await self._audit(name, "promote", str(ctx.author), str(user), f"{role_name(current)} → {role_name(new_role)}")
|
||||
|
||||
@wh_staff.command(name="demote")
|
||||
@WormholeBase.wh_staff.command(name="demote")
|
||||
async def wh_staff_demote(self, ctx: commands.Context, name: str, user: discord.User) -> None:
|
||||
"""Demote a staff member one tier down."""
|
||||
nd = await self._net(name)
|
||||
|
|
@ -144,7 +140,7 @@ class StaffCommands:
|
|||
))
|
||||
await self._audit(name, "demote", str(ctx.author), str(user), f"{role_name(current)} → {label}")
|
||||
|
||||
@wh_staff.command(name="list", aliases=["ls"])
|
||||
@WormholeBase.wh_staff.command(name="list", aliases=["ls"])
|
||||
async def wh_staff_ls(self, ctx: commands.Context, name: str) -> None:
|
||||
"""List all staff in a network with their roles."""
|
||||
nd = await self._net(name)
|
||||
|
|
@ -169,7 +165,7 @@ class StaffCommands:
|
|||
)
|
||||
await ctx.send(embed=em)
|
||||
|
||||
@commands.hybrid_command(name="wh-transfer")
|
||||
@WormholeBase.wh.command(name="transfer")
|
||||
async def wh_transfer(self, ctx: commands.Context, name: str, new_owner: discord.User) -> None:
|
||||
"""Transfer network ownership (owner or bot owner only)."""
|
||||
nd = await self._net(name)
|
||||
|
|
|
|||
|
|
@ -9,17 +9,13 @@ from redbot.core import commands
|
|||
|
||||
from ..models.permissions import Role, requires_role
|
||||
from ..utils import ok_embed, err_embed, info_embed, COLOUR_INFO
|
||||
from ._base import WormholeBase
|
||||
|
||||
|
||||
class ToSCommands:
|
||||
class ToSCommands(WormholeBase):
|
||||
"""Mixin — Terms of Service / rules acceptance gate."""
|
||||
|
||||
@commands.group(name="wh-rules", aliases=["whrules"], invoke_without_command=True)
|
||||
async def wh_rules(self, ctx: commands.Context) -> None:
|
||||
"""Network rules / Terms of Service."""
|
||||
await ctx.send_help(ctx.command)
|
||||
|
||||
@wh_rules.command(name="set")
|
||||
@WormholeBase.wh_rules.command(name="set")
|
||||
@requires_role(Role.ADMIN)
|
||||
async def wh_rules_set(self, ctx: commands.Context, name: str, *, text: str) -> None:
|
||||
"""Set the rules / ToS text."""
|
||||
|
|
@ -27,7 +23,7 @@ class ToSCommands:
|
|||
ns[name]["rules_text"] = text
|
||||
await ctx.send(embed=ok_embed(f"Rules updated for `{name}`."))
|
||||
|
||||
@wh_rules.command(name="require")
|
||||
@WormholeBase.wh_rules.command(name="require")
|
||||
@requires_role(Role.ADMIN)
|
||||
async def wh_rules_require(self, ctx: commands.Context, name: str, enabled: bool = True) -> None:
|
||||
"""Toggle mandatory rules acceptance before using the network."""
|
||||
|
|
@ -37,7 +33,7 @@ class ToSCommands:
|
|||
f"Rules acceptance {'required' if enabled else 'not required'} for `{name}`."
|
||||
))
|
||||
|
||||
@wh_rules.command(name="view")
|
||||
@WormholeBase.wh_rules.command(name="view")
|
||||
async def wh_rules_view(self, ctx: commands.Context, name: str) -> None:
|
||||
"""View the network rules."""
|
||||
nd = await self._net(name)
|
||||
|
|
@ -56,7 +52,7 @@ class ToSCommands:
|
|||
em.set_footer(text="⚠️ You haven't accepted these rules yet. Use `wh accept` or `wh agree`.")
|
||||
await ctx.send(embed=em)
|
||||
|
||||
@commands.hybrid_command(name="wh-accept")
|
||||
@WormholeBase.wh.command(name="accept")
|
||||
async def wh_accept(self, ctx: commands.Context, name: str) -> None:
|
||||
"""Accept the network rules / ToS."""
|
||||
nd = await self._net(name)
|
||||
|
|
@ -68,12 +64,12 @@ class ToSCommands:
|
|||
ns[name].setdefault("rules_accepted", {})[str(ctx.author.id)] = datetime.now(timezone.utc).isoformat()
|
||||
await ctx.send(embed=ok_embed(f"You've accepted the rules for `{name}`. You can now use the relay."))
|
||||
|
||||
@commands.hybrid_command(name="wh-agree")
|
||||
@WormholeBase.wh.command(name="agree")
|
||||
async def wh_agree(self, ctx: commands.Context, name: str) -> None:
|
||||
"""Alias for ``wh accept``."""
|
||||
await self.wh_accept(ctx, name)
|
||||
|
||||
@wh_rules.command(name="reset")
|
||||
@WormholeBase.wh_rules.command(name="reset")
|
||||
@requires_role(Role.ADMIN)
|
||||
async def wh_rules_reset(self, ctx: commands.Context, name: str) -> None:
|
||||
"""Reset all acceptances (force everyone to re-accept)."""
|
||||
|
|
|
|||
|
|
@ -726,9 +726,4 @@ class Wormhole(
|
|||
)
|
||||
await interaction.response.send_message(embed=em, ephemeral=True)
|
||||
|
||||
# ── Root command group ─────────────────────────────────────────────────
|
||||
|
||||
@commands.hybrid_group(name="wh", aliases=["wormhole"], invoke_without_command=True)
|
||||
async def wh(self, ctx: commands.Context) -> None:
|
||||
"""🌀 Wormhole — the ultimate cross-server relay."""
|
||||
await ctx.send_help(ctx.command)
|
||||
# ── Root command group is defined in commands/_base.py ────────────────
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue