I have a ban command which uses discord.User cog as to ban members who are not in the guild, but I want to add role hierarchy but when I checked the docs there was no attribute for it, is there a way to do both? Have role hierarchy and be able to ban users who are not in the guild
You can iterate through the roles of the user and check if he has a role in a list. I prefer to use the role IDs since it can't be changed.
Use typing.Union to either get a member, or the id if the user is not in the server
from typing import Union
#client.command()
#commands.bot_has_permissions(ban_members=True)
#commands.has_permissions(ban_members=True)
async def ban(ctx, user: Union[discord.Member, int]):
if isinstance(user, int):
# user is not in guild -> ban him by id
pass
else:
whitelisted_roles = [123456, 456789, 789012] # List of Mod roles
for role in user.roles:
if role.id in whitelisted_roles:
return await ctx.send("You can't ban this user! He is a moderator!")
else:
pass
# ban the member
Welcome to StackOwerflow!
Yes, it's possible to check role hierarchy as well as ban users with their user_ids.
I recommend taking a looking into the answer by Guddi.
First and formost:
You need a check role heirarchy.
To do that, here's the code:
if not (user.guild_permissions.administrator and user.top_role.position > ctx.me.top_role.position and user.top_role.position > ctx.author.top_role.position):
user.ban()
To ban the user who is not in the guild,
if isinstance(user, int):
user = await bot.fetch_user(user)
await ctx.guild.ban(user)
I hope this is helpful.
Related
Blockquote
I have a bug, I created a bot that issues a role when entering the members server, but sometimes the bot is offline and cannot issue a role
Therefore, I wanted the bot to display a role when the bot is started if the member does not have a role, and to do nothing if the member already has a role
I tried it but it doesn't work and yes I work because of the cogenter image description here
#commands.Cog.listener()
async def on_ready(self, guild: discord.Guild):
role = discord.utils.get(guild.roles, id=775777298111791104)
for m in guild.members:
for r in role.guild.members:
if m.guild.roles != r.get_role(775777298111791104):
print("Ok")
await m.add_roles(role)
=======================================================================
async def setup(bot):
await bot.add_cog(JoinMemberMessages(bot))
I think there's a few fundamental issues with your code.
You're looping over the guild members and then for each guild member you're starting another loop where you're looping over the guild members again? Then you're checking if all the server's role is equal to one particular role?
Additionally, the on_ready event doesn't take guild as a parameter
Your code doesn't quite do what you suggest it's trying to do.
async def on_ready(self):
# if your client/bot is instantiated as another var - then change this
# perhaps if it's `client` or `self.bot` or whatever
guild = await bot.fetch_guild(YOUR_GUILD_ID)
role = discord.utils.get(guild.roles, id=MY_ROLE_ID)
for member in guild.members:
member_roles = member.roles
member_role_ids = [role.id for role in member_roles]
if MY_ROLE_ID in member_roles_ids:
# user already has our role
continue
await member.add_roles(role)
print(f"Given {member.name} the {role.name} role")
Replace CAPITAL_VARIABLES with yours or the relevant magic numbers.
Here, we loop over the members and check they don't have the existing role ID; and assign it to them if they don't.
Perhaps check the docs:
on_ready
discord.Guild
discord.Member
I am trying to create a command that can ban people on the Server and those who are not on the server. But there is a problem: If I use async def ban(ctx, member: discord.Member, *, reason): to use the "roles" attribute, then it will not be able to ban those who are not on the server. If i use async def ban(ctx, member: discord.User, *, reason): i will not be able to use the "roles" attribute because it is not an attribute.
Why am I doing this? I am trying to make it so that Server Moderators cannot ban those who have Moderator roles
Code:
async def ban(ctx, member: discord.User = None, *, reason=None):
if get(ctx.author.roles, id=866038959980544050) or get(ctx.author.roles, id=866436325503008768) or get(
ctx.author.roles, id=866441730631008316) or ctx.author.guild_permissions.administrator: # Check if the author has the Role "Moderator", "Admin", etc.
if get(member.roles, id=867371024466968596) or get(member.roles, id=867132420489871411) and not ctx.author.guild_permissions.administrator: # Check if the member has the Role "Moderator", "Admin", etc.
await ctx.send("You cannot ban this user.")
Assuming that you use discord.ext.commands, you could use a typing.Union converter to ensure that the argument is either a user or a member.
import typing
[...]
async def ban(ctx, user: typing.Union[discord.Member, discord.User]):
Note that order matters: By having discord.Member first, it tries to apply this converter first before trying discord.User, thus prioritising conversion to a member over conversion to a user (which should be what you want).
To distinguish between the two cases, you can now check whether user is of type discord.Member and perform your checks on it.
if type(user) is discord.Member:
if YOUR_CHECKS:
await ctx.send('You cannot ban this user')
return
# Perform ban
await ctx.send('Ban successful')
When testing, I discovered that the command library will give you a numerical user id instead of a real user and shows
Failed fetching discord object! Passing ID instead. as a warning. If you need more than just the user id, you could convert it to a User object using
if type(user) is int:
user = await bot.fetch_user(user)
if user is None:
await ctx.send('User not found')
return
Note that fetch_user is an API call and you might want to avoid it. See the docs for more info.
One way of doing this would be to check if the given member is in the current guild. If this is True, you can create a new member object with their id or with another prefered method, otherwise you can assume that they do not have the Moderator role. For simplicity, I only included checking for a single role, but you can tweak this in the way you want to do it. Other than that, everything else is explained in further detail in the code below.
if member in ctx.guild.members: # checks if the provided member is in the current server
member = ctx.guild.get_member(member.id) # Get the member object of the user
if get(member.roles, id=866038959980544050): # Check if this role is in the member's roles
await ctx.send("This member has <#&866038959980544050>")
else:
await ctx.send("This member does not have <#&866038959980544050>")
return # returns, since member was in the server
# This happens if the provided member is not in the current server
await ctx.send("This member, who is not in this server, does not have <#&866038959980544050>")
You must use this
#bot.command(...)
#commands.has_any_role(role id)
...
I asked this question before, but due to my next to zero experience with stack-overflow it messed it up. So i will rewrite the question with the anwser so people looking for this can have it right away.
So my question was, how can i whitelist role from being banned. Now later, with more experience with discord.py i can tell you the anwser listed down below is the way to do it.
The working code: Credit to CaptAngryEyes
#bot.command()
async def ban(ctx, member : discord.Member):
whitelisted_roles = [728345678923456, 923478569378456, 8923475627893456] # Put the role IDs here
for role in member.roles:
if role.id in whitelisted_roles:
await ctx.send("You can't ban this user! He is a moderator!")
return
else:
# Ban code goes here...
pass
You can iterate through the roles of the user and check if he has a role in a list. I use the role IDs since it can't be changed.
#bot.command()
async def ban(ctx, member : discord.Member):
whitelisted_roles = [728345678923456, 923478569378456, 8923475627893456] # Put the role IDs here
for role in member.roles:
if role.id in whitelisted_roles:
await ctx.send("You can't ban this user! He is a moderator!")
return
else:
# Ban code goes here...
pass
If he has a "whitelisted" role we just return nothing and the command ends.
is there a way to send all of the mentioned person's roles to a channel?
Start of my code:
#client.command()
#commands.has_role("Enhanced Permissions")
async def softban(ctx, user : discord.Member,
Not sure what to do next
roles = user.roles
roles = [role.name for role in roles]
await ctx.send(f"```{','.join(roles)}```"
This will fetch the roles belonging to user and print them within codeblocks.
i can't get my bot to add roles. what am i doing wrong here?
class MyClient(discord.Client):
async def on_voice_state_update(member, before, after):
role = get(member.server.roles, name="babbelaar")
if after.channel is None:
member.add_roles([role.id])
else:
member.remove_roles([role.id])
i want a user that joins a voice channel to get a certain role, and that role to be removed after the user leaves the voice channel
You need to await adding/removing roles, and pass the roles as an argument list of Role objects (instead of passing a list):
await member.add_roles(role)