Jo_
Jo_

Reputation: 91

Discord bot fails to add a role to a user using discord.py

I simply want my bot to add a role to a user in discord. Although the syntax seems simply, apparently I'm doing something wrong.I'm new to python, so I'd appreciate some pointers in the right direction!

bot = commands.Bot(command_prefix='!')

def getdiscordid(discordname):
    for guild in bot.guilds:
        for member in guild.members:
            if member.name == discordname:
                return member.id


@bot.command(name='role')
async def role(ctx):
    await ctx.message.channel.send("Testing roles")
    discordid = getdiscordid("Waldstein")
    print ("id: " , discordid)
    member = bot.get_user(discordid)
    print ("member: ", member)
    role = get(ctx.message.guild.roles, name="Egg")
    print("role: ", role.name)
    await  member.add_roles(role)
    print("done")

# error handler
@bot.event
async def on_command_error(ctx, error):
    if isinstance(error, commands.errors.CheckFailure):
        await ctx.send(error)


bot.run(TOKEN)

In this example he successfully retrieves the member, he can't find the Egg role, and doesn't add the role. [Edit: I corrected the line to retrieve the role, that works but still no added role. Added the error handler]

Upvotes: 2

Views: 939

Answers (2)

Diggy.
Diggy.

Reputation: 6944

For the answer's sake, I'm writing the whole discord.utils.get instead of just get. Here's your command rewritten:

import discord

@bot.command()
async def role(ctx):
    await ctx.send("Testing roles!")
    member = discord.utils.get(bot.get_all_members(), name="Waldstein")
             # be careful when getting objects via their name, as if there are duplicates,
             # then it might not return the one you expect

    print(f"id: {member.id}")
    print(f"member: {member}")
    role = discord.utils.get(ctx.guild.roles, name="Egg") # you can do it by ID as well
    print(f"role: {role.name}")
    await member.add_roles(role) # adding to a member object, not a user
    print("Done!")

If this doesn't work, try printing out something like so:

print(ctx.guild.roles)

and it should return each role that the bot can see. This way you can manually debug it.

One thing that might cause this issue is that if the bot doesn't have the necessary permissions, or if its role is below the role you're attempting to get i.e. Egg is in position 1 in the hierarchy, and the bot's highest role is in position 2.


References:

Upvotes: 0

DaveStSomeWhere
DaveStSomeWhere

Reputation: 2540

The key issue is that add_roles() adds roles to a Member object not a user.

Made a couple of tweaks...

  1. Changed the get id to get member and return the member object.
  2. changed the name of the command to add_role() to avoid using role as the command and a variable.
  3. changed to await member.add_roles(role)

Try:

def get_member(discordname):
    for guild in bot.guilds:
        for member in guild.members:
            if member.name == discordname:
                return member


@bot.command(name='add_role')
async def add_role(ctx):
    await ctx.message.channel.send("Testing roles")
    member = get_member("Waldstein")
    print(f'member is {member} type {type(member)}')
    role = get(ctx.guild.roles, name="Egg")
    print("role: ", role.name)
    await member.add_roles(role)
    print("done")

Upvotes: 2

Related Questions