How do I make a bot in Discord.py that will assign roles present in a role.json file, while using the same command to both remove and add the same role. For example, ?role <rolename> will both add and remove a role, depending on if the user has the role assigned. I'm a bit confused on how to achieve this.
My current bot uses ?roleadd <rolename> ?roleremove <rolename>.
I'm not sure where your role.json file comes into play, but here's how I would implement such a command
#bot.command(name="role")
async def _role(ctx, role: discord.Role):
if role in ctx.author.roles:
await ctx.author.remove_roles(role)
else:
await ctx.author.add_roles(role)
This uses the Role converter to automatically resolve the role object from its name, id, or mention.
This code basically just checks that if the command raiser is the owner of the server or not and then assigns the specified role to him.
#bot.command()
#commands.is_owner()
async def role(ctx, role:discord.Role):
"""Add a role to someone"""
user = ctx.message.mentions[0]
await user.add_roles(role)
await ctx.send(f"{user.name} has been assigned the role:{role.name}")
Let me break the code down:
#bot.command()
#commands.is_owner()
These are just plain function decorators. They are pretty much self-explanatory. But still let me tell.
#bot.command() just defines that it is a command.
#commands.is_owner() checks that the person who has raised that command is the owner.
async def role(ctx, role:discord.Role): > This line defines the function.
user = ctx.message.mentions[0] #I don't know about this line.
await user.add_roles(role) #This line adds the roles to the user.
await ctx.send(f"{user.name} has been assigned the role:{role.name}")
#It just sends a kind of notification that the role has been assigned
Related
I'm new to python, so can someone help me with my code, because it is not working properly. When the user that I want joins it doesn't give it a role. I want to make it work for a specific user only to give a role when joining discord server.
#client.event
async def on_member_join(member):
member = get(member.id, id=member_id)
role = get(member.guild.roles, id=role_id)
await member.id(member)
await member.add_roles(role)
I don't even know why you're making this so complicated.
Since you already have the member as an "argument" you can work with it and don't have to define member again.
We can get the ID of member very easily with member.id. If we want to compare this with a real ID, we do the following:
if member.id = TheIDHere:
# Do what you want to do
The function for the role is correct, yet I cannot find a use for await member.id(member). What is the point of this/has it any use?
How you add the role at the end is also correct, but the code must be indented properly and best you work with an if / else statement, otherwise the bot will still give an error at the end in the console if always the wrong member joins.
The whole code:
#client.event
async def on_member_join(member):
role = discord.utils.get(member.guild.roles, id=IDOfTheRole) # Get the role from member.guild and the id
if member.id == TheIDHere: # If the member.id matches
await member.add_roles(role) # Add the role for the specific user
else: # If it does not match
return # Do nothing
You may also need to enable the members Intent, here are some good posts on that:
https://discordpy.readthedocs.io/en/stable/intents.html
How do I get the discord.py intents to work?
I made a command that anyone in the server can use, but i'm trying to make that when used on me the member loses his highest role and replace it with a specific one. And i'm having a bit of trouble, i can't remove roles from the member, tried the following codes:
role=member.top_role
await member.remove_roles(role)
and
roles=member.roles
role_list=roles[:-1]
await member.edit(roles=role_list)
edit:
here's the command i'm using to test if the "removing role function" is working:
#client.command()
async def take(ctx , member:discord.Member):
roles = member.roles
roles.reverse()
top_role = roles[0]
await member.remove_roles(top_role)
await ctx.send('top role removed')
I tried these and nothing happened, no errors, nothing. I made some tests dividing the code in parts and all of it works ok until the parts "await member.remove_roles(role)" in the first case and "await member.edit(roles=role_list)" in the second. Am i missing something for it to work?
edit: answer updated.
The ctx.author is a member.
You can find everything in the official Documentation. Discord.py
#client.command()
async def take(ctx):
roles = ctx.author.roles #list of roles, lowest role first
roles.reverse() #list of roles, highest role first
top_role = roles[0] #first entry of list
await ctx.author.remove_roles(top_role)
await ctx.send('top role removed')
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]
The key issue is that add_roles() adds roles to a Member object not a user.
Made a couple of tweaks...
Changed the get id to get member and return the member object.
changed the name of the command to add_role() to avoid using role as the command and a variable.
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")
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:
Guild.roles
Client.get_all_members()
Member.add_roles()
utils.get()
commands.Context - I noticed you were using some superfluous code, take a look at this to see all the attributes of ctx
I have seen that you can add a role using a bot using discord.py. I want to make my code so that you can add roles with multiple words as its name so you don't get errors like 'Role "Chief" not found' when the command was -giverole Chief Executive Officer. I also want to add another parameter in which you ping the user you want to give the role to.
This is for my discord server. I have got a working code that can give a role to you (whoever executes the command) and the role can only be one word: E.g. 'Members'
#client.command(pass_context=True)
async def giverole(ctx, role: discord.Role):
await client.add_roles(ctx.message.author, role)
Input: -giverole <mention_user> <role_name> (must be compatible to give a role that is multiple words)
Output: I can sort out a message that it sends.
You can use a converter to get the Member to send the role to just like you use it to get the Role itself. To accept multiple-word roles, use the keyword-only argument syntax. You can also use role mentions when invoking the command. (e.g. !giverole #Patrick #Chief Executive Officer).
#client.command(pass_context=True)
async def giverole(ctx, member: discord.Member, *, role: discord.Role):
await client.say(f"Giving the role {role.mention} to {member.mention}")
await client.add_roles(member, role)
You can use discord.utils.get to get the role from a string, in this case role_name
#client.command(pass_context=True)
async def giverole(ctx, *,role_name:str):
role = discord.utils.get(ctx.message.server.roles, name=role_name)
await client.add_roles(ctx.message.author, role)
how i can set kick command with a role use just that Moderator role will can use
my kick command :
#client.command(pass_context = True)
async def kick(ctx, userName: discord.User):
"""Kick A User from server"""
await client.kick(userName)
await client.say("__**Successfully User Has Been Kicked!**__")
You can use the commands.has_permissions decorator to ensure the caller has a specific permission.
#client.command(...)
#commands.has_permissions(kick_members=True)
async def kick(ctx, ...):
pass
Just a word of warning though, according to the function docstring, it checks for the user having any required permission instead of all.
It is also recommended to add the bot_has_permissions check too to make sure it can actually kick users too.