feat: Implement modals for user moderation actions in context menus

This commit is contained in:
Slipstream 2025-05-14 10:11:14 -06:00
parent c251fafd73
commit c2b935076b
Signed by: slipstream
GPG Key ID: 13E498CE010AC6FD

View File

@ -1126,48 +1126,218 @@ class ModerationCog(commands.Cog):
async def on_ready(self):
print(f'{self.__class__.__name__} cog has been loaded.')
# Modals for context menu commands
class BanModal(discord.ui.Modal, title="Ban User"):
def __init__(self, member: discord.Member):
super().__init__()
self.member = member
reason = discord.ui.TextInput(
label="Reason",
placeholder="Enter reason for ban",
style=discord.TextStyle.paragraph,
required=False,
max_length=512,
)
delete_days = discord.ui.TextInput(
label="Delete message history (days)",
placeholder="0-7 (default 0)",
required=False,
max_length=1,
)
async def on_submit(self, interaction: discord.Interaction):
await interaction.response.defer(ephemeral=True) # Defer the modal submission
cog = interaction.client.get_cog("ModerationCog")
if cog:
reason = self.reason.value or "No reason provided"
delete_days = int(self.delete_days.value) if self.delete_days.value and self.delete_days.value.isdigit() else 0
# Call the existing ban callback
await cog.moderate_ban_callback(interaction, self.member, reason=reason, delete_days=delete_days)
else:
await interaction.followup.send("Error: Moderation cog not found.", ephemeral=True)
class KickModal(discord.ui.Modal, title="Kick User"):
def __init__(self, member: discord.Member):
super().__init__()
self.member = member
reason = discord.ui.TextInput(
label="Reason",
placeholder="Enter reason for kick",
style=discord.TextStyle.paragraph,
required=False,
max_length=512,
)
async def on_submit(self, interaction: discord.Interaction):
await interaction.response.defer(ephemeral=True) # Defer the modal submission
cog = interaction.client.get_cog("ModerationCog")
if cog:
reason = self.reason.value or "No reason provided"
# Call the existing kick callback
await cog.moderate_kick_callback(interaction, self.member, reason=reason)
else:
await interaction.followup.send("Error: Moderation cog not found.", ephemeral=True)
class TimeoutModal(discord.ui.Modal, title="Timeout User"):
def __init__(self, member: discord.Member):
super().__init__()
self.member = member
duration = discord.ui.TextInput(
label="Duration",
placeholder="e.g., 1d, 2h, 30m, 60s",
required=True,
max_length=10,
)
reason = discord.ui.TextInput(
label="Reason",
placeholder="Enter reason for timeout",
style=discord.TextStyle.paragraph,
required=False,
max_length=512,
)
async def on_submit(self, interaction: discord.Interaction):
await interaction.response.defer(ephemeral=True) # Defer the modal submission
cog = interaction.client.get_cog("ModerationCog")
if cog:
duration = self.duration.value
reason = self.reason.value or "No reason provided"
# Call the existing timeout callback
await cog.moderate_timeout_callback(interaction, self.member, duration=duration, reason=reason)
else:
await interaction.followup.send("Error: Moderation cog not found.", ephemeral=True)
class RemoveTimeoutModal(discord.ui.Modal, title="Remove Timeout"):
def __init__(self, member: discord.Member):
super().__init__()
self.member = member
reason = discord.ui.TextInput(
label="Reason",
placeholder="Enter reason for removing timeout",
style=discord.TextStyle.paragraph,
required=False,
max_length=512,
)
async def on_submit(self, interaction: discord.Interaction):
await interaction.response.defer(ephemeral=True) # Defer the modal submission
cog = interaction.client.get_cog("ModerationCog")
if cog:
reason = self.reason.value or "No reason provided"
# Call the existing remove timeout callback
await cog.moderate_remove_timeout_callback(interaction, self.member, reason=reason)
else:
await interaction.followup.send("Error: Moderation cog not found.", ephemeral=True)
# Context menu commands must be defined at module level
@app_commands.context_menu(name="Ban User")
async def ban_user_context_menu(interaction: discord.Interaction, member: discord.Member):
"""Bans the selected user."""
cog = interaction.client.get_cog("ModerationCog")
if cog:
# Call the existing ban callback with default reason and delete_days
await cog.moderate_ban_callback(interaction, member, reason="Banned via context menu", delete_days=0)
else:
await interaction.response.send_message("Error: Moderation cog not found.", ephemeral=True)
"""Bans the selected user via a modal."""
# Check permissions before showing the modal
if not interaction.user.guild_permissions.ban_members:
await interaction.response.send_message("❌ You don't have permission to ban members.", ephemeral=True)
return
if not interaction.guild.me.guild_permissions.ban_members:
await interaction.response.send_message("❌ I don't have permission to ban members.", ephemeral=True)
return
if interaction.user.top_role <= member.top_role and interaction.user.id != interaction.guild.owner_id:
await interaction.response.send_message("❌ You cannot ban someone with a higher or equal role.", ephemeral=True)
return
if interaction.guild.me.top_role <= member.top_role:
await interaction.response.send_message("❌ I cannot ban someone with a higher or equal role than me.", ephemeral=True)
return
if member.id == interaction.user.id:
await interaction.response.send_message("❌ You cannot ban yourself.", ephemeral=True)
return
if member.id == interaction.client.user.id:
await interaction.response.send_message("❌ I cannot ban myself.", ephemeral=True)
return
modal = BanModal(member)
await interaction.response.send_modal(modal)
@app_commands.context_menu(name="Kick User")
async def kick_user_context_menu(interaction: discord.Interaction, member: discord.Member):
"""Kicks the selected user."""
cog = interaction.client.get_cog("ModerationCog")
if cog:
# Call the existing kick callback with default reason
await cog.moderate_kick_callback(interaction, member, reason="Kicked via context menu")
else:
await interaction.response.send_message("Error: Moderation cog not found.", ephemeral=True)
"""Kicks the selected user via a modal."""
# Check permissions before showing the modal
if not interaction.user.guild_permissions.kick_members:
await interaction.response.send_message("❌ You don't have permission to kick members.", ephemeral=True)
return
if not interaction.guild.me.guild_permissions.kick_members:
await interaction.response.send_message("❌ I don't have permission to kick members.", ephemeral=True)
return
if interaction.user.top_role <= member.top_role and interaction.user.id != interaction.guild.owner_id:
await interaction.response.send_message("❌ You cannot kick someone with a higher or equal role.", ephemeral=True)
return
if interaction.guild.me.top_role <= member.top_role:
await interaction.response.send_message("❌ I cannot kick someone with a higher or equal role than me.", ephemeral=True)
return
if member.id == interaction.user.id:
await interaction.response.send_message("❌ You cannot kick yourself.", ephemeral=True)
return
if member.id == interaction.client.user.id:
await interaction.response.send_message("❌ I cannot kick myself.", ephemeral=True)
return
modal = KickModal(member)
await interaction.response.send_modal(modal)
@app_commands.context_menu(name="Timeout User")
async def timeout_user_context_menu(interaction: discord.Interaction, member: discord.Member):
"""Timeouts the selected user for a short duration."""
cog = interaction.client.get_cog("ModerationCog")
if cog:
# For simplicity in context menu, apply a default short timeout (e.g., 5 minutes)
# A more complex implementation might use a modal to ask for duration/reason
await cog.moderate_timeout_callback(interaction, member, duration="5m", reason="Timed out via context menu")
else:
await interaction.response.send_message("Error: Moderation cog not found.", ephemeral=True)
"""Timeouts the selected user via a modal."""
# Check permissions before showing the modal
if not interaction.user.guild_permissions.moderate_members:
await interaction.response.send_message("❌ You don't have permission to timeout members.", ephemeral=True)
return
if not interaction.guild.me.guild_permissions.moderate_members:
await interaction.response.send_message("❌ I don't have permission to timeout members.", ephemeral=True)
return
if interaction.user.top_role <= member.top_role and interaction.user.id != interaction.guild.owner_id:
await interaction.response.send_message("❌ You cannot timeout someone with a higher or equal role.", ephemeral=True)
return
if interaction.guild.me.top_role <= member.top_role:
await interaction.response.send_message("❌ I cannot timeout someone with a higher or equal role than me.", ephemeral=True)
return
if member.id == interaction.user.id:
await interaction.response.send_message("❌ You cannot timeout yourself.", ephemeral=True)
return
if member.id == interaction.client.user.id:
await interaction.response.send_message("❌ I cannot timeout myself.", ephemeral=True)
return
modal = TimeoutModal(member)
await interaction.response.send_modal(modal)
@app_commands.context_menu(name="Remove Timeout")
async def remove_timeout_context_menu(interaction: discord.Interaction, member: discord.Member):
"""Removes timeout from the selected user."""
cog = interaction.client.get_cog("ModerationCog")
if cog:
# Call the existing remove timeout callback with default reason
await cog.moderate_remove_timeout_callback(interaction, member, reason="Timeout removed via context menu")
else:
await interaction.response.send_message("Error: Moderation cog not found.", ephemeral=True)
"""Removes timeout from the selected user via a modal."""
# Check permissions before showing the modal
if not interaction.user.guild_permissions.moderate_members:
await interaction.response.send_message("❌ You don't have permission to remove timeouts.", ephemeral=True)
return
if not interaction.guild.me.guild_permissions.moderate_members:
await interaction.response.send_message("❌ I don't have permission to remove timeouts.", ephemeral=True)
return
# Check if the member is timed out before showing the modal
if not member.timed_out_until:
await interaction.response.send_message("❌ This member is not timed out.", ephemeral=True)
return
modal = RemoveTimeoutModal(member)
await interaction.response.send_modal(modal)
async def setup(bot: commands.Bot):