diff --git a/bot/config.py b/bot/config.py index 0319e95b..d31adeb7 100644 --- a/bot/config.py +++ b/bot/config.py @@ -1,6 +1,5 @@ import json import logging -from typing import List from pydantic import BaseModel, BaseSettings, PostgresDsn, ValidationError, validator @@ -14,7 +13,7 @@ class AoC(BaseModel): class Bot(BaseModel): - commands_channels_ids: List[int] + commands_channels_ids: list[int] games_channel_id: int # #bot-games token: str @@ -48,7 +47,7 @@ class Guild(BaseModel): class Moderation(BaseModel): - admin_roles_ids: List[int] + admin_roles_ids: list[int] staff_role_id: int @validator("admin_roles_ids", pre=True) diff --git a/bot/extensions/selectable_roles/commands.py b/bot/extensions/selectable_roles/commands.py index 1a733459..2400e199 100644 --- a/bot/extensions/selectable_roles/commands.py +++ b/bot/extensions/selectable_roles/commands.py @@ -17,13 +17,28 @@ def __init__(self, bot: core.DiscordBot): self.bot.add_view(self._create_selectable_role_view) @app_commands.command() - async def create(self, interaction: core.InteractionType, title: str, channel: discord.TextChannel = None): + async def create( + self, + interaction: core.InteractionType, + title: str, + channel: discord.TextChannel = None, + description: str = None, + footer: str = None, + ): """Create a new selectable role message""" if channel is None: channel = interaction.channel - await channel.send(title, view=self._create_selectable_role_view) + embed = discord.Embed( + title=title, + description=description, + color=discord.Color.gold(), + ) + if footer: + embed.set_footer(text=footer) + + await channel.send(embed=embed, view=self._create_selectable_role_view) await interaction.response.send_message( "Successfully created selectable role message! Please add role options to it by using /selectable-role add", ephemeral=True, @@ -34,7 +49,7 @@ async def add( self, interaction: core.InteractionType, message: app_commands.Transform[discord.Message, MessageTransformer], - text: str, + description: str, role: discord.Role, emoji: str, ): @@ -54,11 +69,15 @@ async def add( view = CreateSelectableRoleView(timeout=None) view.add_item( SelectableRoleOptions( - options + [discord.SelectOption(label=role.name, description=text, value=str(role.id), emoji=emoji)] + options + + [discord.SelectOption(label=role.name, description=description, value=str(role.id), emoji=emoji)] ) ) - await message.edit(view=view) + embed = message.embeds[0] + embed.add_field(name=f"{emoji} {role.name}", value=description, inline=False) + + await message.edit(embed=embed, view=view) await interaction.response.send_message("Successfully added role to selectable role message!", ephemeral=True) @app_commands.command() @@ -76,17 +95,26 @@ async def remove( ) view = discord.ui.View.from_message(message, timeout=None) + embed = message.embeds[0] options = [] if view.children: options = view.children[0].options - options = [option for option in options if option.value != str(role.id)] + + try: + role_index = [option.value for option in options].index(str(role.id)) + options.pop(role_index) + embed.remove_field(role_index) + except ValueError: + return await interaction.response.send_message( + "The role you provided is not a selectable role in this message.", ephemeral=True + ) if len(options) == 0: - await message.edit(view=None) + await message.edit(embed=embed, view=None) else: view = CreateSelectableRoleView(timeout=None) view.add_item(SelectableRoleOptions(options)) - await message.edit(view=view) + await message.edit(embed=embed, view=view) await interaction.response.send_message( "Successfully removed role from selectable role message!", ephemeral=True diff --git a/bot/extensions/selectable_roles/views.py b/bot/extensions/selectable_roles/views.py index 81784bd6..5024fc76 100644 --- a/bot/extensions/selectable_roles/views.py +++ b/bot/extensions/selectable_roles/views.py @@ -9,10 +9,16 @@ def __init__(self, options: list[discord.SelectOption]): super().__init__( placeholder="Select a role", custom_id=CreateSelectableRoleView.DROPDOWN_CUSTOM_ID, + min_values=0, options=options, ) async def callback(self, interaction: core.InteractionType): + if not self.values: + roles = [interaction.guild.get_role(int(option.value)) for option in self.options] + await interaction.user.remove_roles(*roles, reason="Selectable role") + return await interaction.response.send_message("Successfully removed the role from you!", ephemeral=True) + selected_role_id = int(self.values[0]) role = interaction.guild.get_role(selected_role_id) diff --git a/utils/transformers.py b/utils/transformers.py index aef3ab91..74d831ef 100644 --- a/utils/transformers.py +++ b/utils/transformers.py @@ -9,11 +9,18 @@ class MessageTransformer(app_commands.Transformer): + """ + Transform any of the given formats to a Message instance: + + - 1176092816762486784 # message_id + - 1024375283857506436/1176092816762486784 # channel_id/message_id + - https://discord.com/channels/1024375277679284315/1024375283857506436/1176092816762486784 # message_url + """ + async def transform(self, interaction: core.InteractionType, value: str, /): + parts: list[str] = value.split("/") try: - parts: list[str] = value.split("/") - - if len(parts) != 2: + if len(parts) == 1: return await interaction.channel.fetch_message(int(value)) message_id = int(parts[-1]) @@ -22,7 +29,11 @@ async def transform(self, interaction: core.InteractionType, value: str, /): channel = interaction.guild.get_channel(channel_id) return await channel.fetch_message(message_id) except (ValueError, TypeError, IndexError, AttributeError): - await interaction.response.send_message("Please provide a valid message ID.", ephemeral=True) + if len(parts) == 1: + message = "Please provide a valid message ID." + else: + message = "Please provide a valid message URL." + await interaction.response.send_message(message, ephemeral=True) except discord.HTTPException: await interaction.response.send_message("Sorry, I couldn't find that message...", ephemeral=True)