|
11 | 11 | from bs4 import BeautifulSoup |
12 | 12 | from discord import app_commands |
13 | 13 | from discord.ext import commands |
| 14 | +from discord.ui import Button, View |
14 | 15 |
|
15 | 16 | from ..utils.helpers import format_latency, create_embed, parse_channel_config |
16 | 17 | from ..utils.logger import main_logger as logger |
17 | 18 |
|
18 | 19 |
|
| 20 | +class DeleteExtraChannelsView(View): |
| 21 | + """View for confirming deletion of extra channels.""" |
| 22 | + |
| 23 | + def __init__(self, extra_channels, category_name, timeout=60): |
| 24 | + super().__init__(timeout=timeout) |
| 25 | + self.extra_channels = extra_channels |
| 26 | + self.category_name = category_name |
| 27 | + |
| 28 | + # Add delete button |
| 29 | + delete_button = Button( |
| 30 | + label="🗑️ Delete Extra Channels", |
| 31 | + style=discord.ButtonStyle.danger, |
| 32 | + custom_id="delete_extra_channels" |
| 33 | + ) |
| 34 | + delete_button.callback = self.delete_callback |
| 35 | + self.add_item(delete_button) |
| 36 | + |
| 37 | + async def delete_callback(self, interaction: discord.Interaction): |
| 38 | + """Handle delete button click.""" |
| 39 | + # Check if user has manage channels permission |
| 40 | + if not interaction.user.guild_permissions.manage_channels: |
| 41 | + embed = create_embed( |
| 42 | + title="❌ Permission Denied", |
| 43 | + description="You need the 'Manage Channels' permission to delete channels.", |
| 44 | + color=discord.Color.red() |
| 45 | + ) |
| 46 | + await interaction.response.send_message(embed=embed, ephemeral=True) |
| 47 | + return |
| 48 | + |
| 49 | + # Create confirmation embed |
| 50 | + channel_list = "\n".join([f"• {channel.mention}" for channel in self.extra_channels]) |
| 51 | + embed = create_embed( |
| 52 | + title="⚠️ Confirm Deletion", |
| 53 | + description=f"Are you sure you want to delete the following channels from **{self.category_name}**?\n\n{channel_list}\n\n**This action is irreversible!**", |
| 54 | + color=discord.Color.orange() |
| 55 | + ) |
| 56 | + |
| 57 | + # Create confirmation view |
| 58 | + confirm_view = ConfirmDeleteView(self.extra_channels, self.category_name) |
| 59 | + await interaction.response.send_message(embed=embed, view=confirm_view, ephemeral=True) |
| 60 | + |
| 61 | + |
| 62 | +class ConfirmDeleteView(View): |
| 63 | + """View for final confirmation of channel deletion.""" |
| 64 | + |
| 65 | + def __init__(self, extra_channels, category_name, timeout=60): |
| 66 | + super().__init__(timeout=timeout) |
| 67 | + self.extra_channels = extra_channels |
| 68 | + self.category_name = category_name |
| 69 | + |
| 70 | + # Add confirm and cancel buttons |
| 71 | + confirm_button = Button( |
| 72 | + label="✅ Yes, Delete All", |
| 73 | + style=discord.ButtonStyle.danger, |
| 74 | + custom_id="confirm_delete" |
| 75 | + ) |
| 76 | + confirm_button.callback = self.confirm_callback |
| 77 | + |
| 78 | + cancel_button = Button( |
| 79 | + label="❌ Cancel", |
| 80 | + style=discord.ButtonStyle.secondary, |
| 81 | + custom_id="cancel_delete" |
| 82 | + ) |
| 83 | + cancel_button.callback = self.cancel_callback |
| 84 | + |
| 85 | + self.add_item(confirm_button) |
| 86 | + self.add_item(cancel_button) |
| 87 | + |
| 88 | + async def confirm_callback(self, interaction: discord.Interaction): |
| 89 | + """Handle confirm button click.""" |
| 90 | + deleted_channels = [] |
| 91 | + failed_channels = [] |
| 92 | + |
| 93 | + # Delete each channel |
| 94 | + for channel in self.extra_channels: |
| 95 | + try: |
| 96 | + channel_name = channel.name |
| 97 | + await channel.delete() |
| 98 | + deleted_channels.append(channel_name) |
| 99 | + logger.info("Deleted extra channel '%s' from category '%s'", channel_name, self.category_name) |
| 100 | + except Exception as e: |
| 101 | + failed_channels.append(channel.name) |
| 102 | + logger.error("Failed to delete channel '%s': %s", channel.name, e) |
| 103 | + |
| 104 | + # Create result embed |
| 105 | + if deleted_channels: |
| 106 | + embed = create_embed( |
| 107 | + title="✅ Channels Deleted", |
| 108 | + description=f"Successfully deleted {len(deleted_channels)} extra channels from **{self.category_name}**", |
| 109 | + color=discord.Color.green() |
| 110 | + ) |
| 111 | + |
| 112 | + if deleted_channels: |
| 113 | + deleted_list = "\n".join([f"• #{name}" for name in deleted_channels]) |
| 114 | + embed.add_field(name="Deleted Channels", value=deleted_list, inline=False) |
| 115 | + |
| 116 | + if failed_channels: |
| 117 | + failed_list = "\n".join([f"• #{name}" for name in failed_channels]) |
| 118 | + embed.add_field(name="Failed to Delete", value=failed_list, inline=False) |
| 119 | + else: |
| 120 | + embed = create_embed( |
| 121 | + title="❌ Deletion Failed", |
| 122 | + description="Failed to delete any channels. Please check permissions and try again.", |
| 123 | + color=discord.Color.red() |
| 124 | + ) |
| 125 | + |
| 126 | + await interaction.response.edit_message(embed=embed, view=None) |
| 127 | + |
| 128 | + async def cancel_callback(self, interaction: discord.Interaction): |
| 129 | + """Handle cancel button click.""" |
| 130 | + embed = create_embed( |
| 131 | + title="❌ Deletion Cancelled", |
| 132 | + description="Channel deletion was cancelled.", |
| 133 | + color=discord.Color.blue() |
| 134 | + ) |
| 135 | + await interaction.response.edit_message(embed=embed, view=None) |
| 136 | + |
| 137 | + |
19 | 138 | class General(commands.Cog): |
20 | 139 | """General utility commands.""" |
21 | 140 |
|
@@ -404,7 +523,13 @@ async def createcategory_slash(self, interaction: discord.Interaction, yaml_path |
404 | 523 | channel_list = "\n".join([f"• {channel.mention} (not in YAML)" for channel in extra_channels]) |
405 | 524 | embed.add_field(name="Extra Channels (Not in YAML)", value=channel_list, inline=False) |
406 | 525 |
|
407 | | - await interaction.followup.send(embed=embed) |
| 526 | + # Add delete button if there are extra channels |
| 527 | + if extra_channels: |
| 528 | + delete_view = DeleteExtraChannelsView(extra_channels, existing_category.name) |
| 529 | + await interaction.followup.send(embed=embed, view=delete_view) |
| 530 | + else: |
| 531 | + await interaction.followup.send(embed=embed) |
| 532 | + |
408 | 533 | logger.info("Category '%s' processed: %d created, %d updated, %d skipped, %d extra", |
409 | 534 | category_config['name'], len(created_channels), len(updated_channels), |
410 | 535 | len(skipped_channels), len(extra_channels)) |
@@ -859,7 +984,12 @@ async def createcategory(self, ctx: commands.Context) -> None: |
859 | 984 | if extra_channels: |
860 | 985 | channel_list = "\n".join([f"• {channel.mention} (not in YAML)" for channel in extra_channels]) |
861 | 986 | embed.add_field(name="Extra Channels (Not in YAML)", value=channel_list, inline=False) |
862 | | - |
| 987 | + # Add delete button if there are extra channels |
| 988 | + if extra_channels: |
| 989 | + delete_view = DeleteExtraChannelsView(extra_channels, existing_category.name) |
| 990 | + await ctx.send(embed=embed, view=delete_view) |
| 991 | + else: |
| 992 | + await ctx.send(embed=embed) |
863 | 993 | await ctx.send(embed=embed) |
864 | 994 | logger.info("Category '%s' processed: %d created, %d updated, %d skipped, %d extra", |
865 | 995 | category_config['name'], len(created_channels), len(updated_channels), |
|
0 commit comments