discorddiscord.py

How do I get my discord bot to accept two roles for a command?


This is my code

@bot.command()
async def modcmds(ctx):
    role = discord.utils.get(ctx.guild.roles, name="🎉 Event Staff Team")
    if role in ctx.author.roles:
        embed = discord.Embed(title="Mod Commands:", description="~lssu (mentions Everyone) \n Description: Announces a London SSU. \n\n ~ssuvote (Mentions here) \n Description: Starts a SSU vote. \n\n Abuse of these commands will result in punishment.")
        await ctx.reply(embed = embed)
        channel = bot.get_channel(1376165325950812222)
        embed = discord.Embed(title="Bot Commmand Log", description=f"The ~modcmds command was just executed by {ctx.author.mention}", color=discord.Color.from_rgb(0, 20, 245))
        await channel.send(embed = embed)

I tried to do this:

role =  discord.utils.get(ctx.guild.roles, name="🎉 Event Staff Team" and "other role"

and

role = discord.utils(ctx.guild.roles, name="🎉 Event Staff Team", name="other role"

but neither of these has worked.


Solution

  • discord.utils.get looks for the first matching element in an iterable. Matching, in the case of the first code block you gave us, means that the name attribute is equal to "🎉 Event Staff Team", and the iterable in your case is ctx.guild.roles. The issue with the code you gave us is that you're trying to get two elements from discord.utils.get, which only returns one.

    You need to run discord.utils.get twice. For example:

    @bot.command()
    async def modcmds(ctx):
        role1 = discord.utils.get(ctx.guild.roles, name="🎉 Event Staff Team")
        role2 = discord.utils.get(ctx.guild.roles, name="other role")
        if role1 in ctx.author.roles or role2 in ctx.author.roles:
            embed = discord.Embed(title="Mod Commands:", description="~lssu (mentions Everyone) \n Description: Announces a London SSU. \n\n ~ssuvote (Mentions here) \n Description: Starts a SSU vote. \n\n Abuse of these commands will result in punishment.")
            await ctx.reply(embed = embed)
            channel = bot.get_channel(1376165325950812222)
            embed = discord.Embed(title="Bot Commmand Log", description=f"The ~modcmds command was just executed by {ctx.author.mention}", color=discord.Color.from_rgb(0, 20, 245))
            await channel.send(embed = embed)
    

    But there's a problem with this approach. This means that every time someone runs the /modcmds command, your bot has to load a big list of all the guild's roles and check each one's name for equality. This is dependent on the names of the roles you're checking for.

    You should save the ID of the roles, just like you've hard-coded the channel ID, and then check them on the member. Here's an example of the better way:

    staff_role_ids = [
        0, # Insert the IDs of the roles here
        0
    ]
    
    @bot.command()
    async def modcmds(ctx):
        if any((ctx.author.get_role(role_id) is not None) for role_id in staff_role_ids):
            embed = discord.Embed(title="Mod Commands:", description="~lssu (mentions Everyone) \n Description: Announces a London SSU. \n\n ~ssuvote (Mentions here) \n Description: Starts a SSU vote. \n\n Abuse of these commands will result in punishment.")
            await ctx.reply(embed = embed)
            channel = bot.get_channel(1376165325950812222)
            embed = discord.Embed(title="Bot Commmand Log", description=f"The ~modcmds command was just executed by {ctx.author.mention}", color=discord.Color.from_rgb(0, 20, 245))
            await channel.send(embed = embed)
    

    Explanation

    The piece of code below tries to use the and operator on two strings. A non-empty string is the same as True when a boolean is expected, so the operator just returns the string on the left.

    role =  discord.utils.get(ctx.guild.roles, name="🎉 Event Staff Team" and "other role")
    

    This code on the other hand sets the name attribute twice. This results in an error.

    role = discord.utils.get(ctx.guild.roles, name="🎉 Event Staff Team", name="other role")
    

    Here's a concrete example in the Python REPL:

    >>> def example(**attrs):
    ...     print(attrs)
    ... 
    >>> example(name="foo" and "bar")
    {'name': 'bar'}
    >>> example(name="foo", name="bar")
      File "<stdin>", line 1
    SyntaxError: keyword argument repeated: name