Search code examples
pythondiscord.pyroles

How to pass context from a command to the callback in discord.py


Partially Finished Product So, essentially, I am trying to create a discord bot that will allow a staff member to request a role. That request will then be sent to an admin-only text channel with a button for approve and a button for decline. The part that I am stuck on is getting the bot to automatically add the role when the Approve button is pressed.

My code so far:

class Request(discord.ui.View):
    def __init__(self):
        super().__init__()
        self.value = None

    
    @discord.ui.button(label = 'Approve', style = discord.ButtonStyle.green, disabled=False, custom_id='Approve')
    async def approve(self, interaction: discord.Interaction, button: discord.ui.Button):
            member = interaction.user
            approve_embed = discord.Embed(title='Request Approved!', description=f'Approved by {member.mention}')
            button.style=discord.ButtonStyle.gray
            await interaction.response.edit_message(embed = approve_embed, view=self)
            self.value = True
            self.stop()


    @discord.ui.button(label = 'Decline', style = discord.ButtonStyle.red, disabled=False, custom_id='Decline')
    async def decline(self, interaction: discord.Interaction, button: discord.ui.Button):
            member = interaction.user
            button.style=discord.ButtonStyle.gray
            decline_embed = discord.Embed(title='Request Declined!', description=f'Declined by {member.mention}')
            await interaction.response.edit_message(embed=decline_embed, view=self)
            self.value = True
            self.stop()

@client.command()
@commands.has_any_role('Mod', '1253697387051094136')
async def roleadd(ctx, role: discord.Role, user: discord.Member):
    channel = client.get_channel(1253704722544853185)
    view = Request()
    await channel.send(f'**New Role Request!** \n {ctx.author.mention} requested to give {role.mention} to {user.mention}', view=view)
    await ctx.reply('*Your request has been submitted*')

Solution

  • You can pass the context from the command to the callback by passing information through the view's arguments. In the Request view define one argument for the user whom you want to give the role and another one for the role itself and set both the arguments as the view's attributes. You can then use this in the callback function to do your desired actions.

    Here is your reformed code:

    class Request(discord.ui.View):
        def __init__(self, user_to_give_role: discord.Member, role_to_give: discord.Role):
            super().__init__()
            self.value = None
            self.user_to_give_role = user_to_give_role
            self.role_to_give = role_to_give
    
        @discord.ui.button(label='Approve', style=discord.ButtonStyle.green, disabled=False, custom_id='Approve')
        async def approve(self, button: discord.Button, interaction: discord.Interaction):
            member = interaction.user
            approve_embed = discord.Embed(
                title='Request Approved!', description=f'Approved by {member.mention}')
            button.style = discord.ButtonStyle.gray
            await interaction.response.edit_message(embed=approve_embed, view=self)
            await self.user_to_give_role.add_roles(self.role_to_give)
            self.value = True
            self.stop()
    
        @discord.ui.button(label='Decline', style=discord.ButtonStyle.red, disabled=False, custom_id='Decline')
        async def decline(self, button: discord.Button, interaction: discord.Interaction):
            member = interaction.user
            button.style = discord.ButtonStyle.gray
            decline_embed = discord.Embed(
                title='Request Declined!', description=f'Declined by {member.mention}')
            await interaction.response.edit_message(embed=decline_embed, view=self)
            self.value = True
            self.stop()
    
    
    @client.command()
    @commands.has_any_role('Mod', '1253697387051094136')
    async def roleadd(ctx, role: discord.Role, user: discord.Member):
        channel = client.get_channel(1253704722544853185)
        view = Request(user_to_give_role=user, role_to_give=role)
        await channel.send(f'**New Role Request!** \n {ctx.author.mention} requested to give {role.mention} to {user.mention}', view=view)
        await ctx.reply('*Your request has been submitted*')