I'm currently trying to add reaction roles to my bot, but I'm having trouble getting the bot to remove roles when the reactions are removed
#client.event
async def on_raw_reaction_add(payload):
print("Reaction Added")
if ((payload.message_id == 874372383736205343) and (payload.emoji.name == '🎓')):
guild = client.get_guild(payload.guild_id)
role = guild.get_role(874364790099836948)
await payload.member.add_roles(role)
#client.event
async def on_raw_reaction_remove(payload):
print("Reaction Removed")
if ((payload.message_id == 874372383736205343) and (payload.emoji.name == '🎓')):
guild = client.get_guild(payload.guild_id)
role = guild.get_role(874364790099836948)
await payload.remove_roles(role)
Adding roles works perfectly as intended but whenever I try removing a reaction I always get some kind of error. I've tried a few different things, but the code that I provided returns "Attribute Error: "RawReactionAddEvent" object has no attribute "remove_roles"
As I said, I've tried things other than remove_roles but none of them worked.
I'm pretty new to discord.py and python as a whole so this is probably a really obvious mistake but I just can't seem to find anything that works.
You'll need to retrieve a member object in order to remove the roles. You're currently trying to remove a role from payload instead of a valid member.
guild = client.get_guild(payload.guild_id)
member = await guild.fetch_member(payload.user_id)
role = guild.get_role(874364790099836948)
await member.remove_roles(role)
As Lukasz points out, you can't use payload.member when a reaction is removed because it is only available when a reaction is added. Docs.
Related
I am trying to make custom commands and thus I am using the on_message event, but one issue I am having is getting the mentioned member in the message, so for example ;give #member.
if message.content.lower().startswith(f";{command}") and message.raw_mentions and content == "None":
mention = message.raw_mentions[0]
if message.content.lower() == f";{command} {mention}":
try:
role = get(message.guild.roles, id=role)
if role:
member = message.guild.get_member(mention)
if member:
await member.add_roles(role)
await message.add_reaction("✅")
except:
return await message.channel.send("I do not have the permissions to give roles, If this is incorrect, You may need to move my role above the role you want to receive/give")
This what I currently have and I haven't been getting any errors, but I'm mainly having issues getting the member that is mentioned.
You don't need the unnecessary steps to get the mention out of the message.
If you want to check if the entered message has user mentions, you can just check the attribute message.mentions. It returns an entire list of all Discord users that was mentioned in the message.
So you can write some code like this:
if message.mentions:
as an example to check if users were mentioned in the message. And of course, you can get every mentioned user directly from the list with a small loop.
Aside from that, your method to get a role is really old. Instead, you should switch to the newer version of it to avoid bugs.
# Check if users are mentioned
if message.mentions:
# check if the role exists
role = message.guild.get_role(int(role))
if role is None:
return
# Add roles to all mentioned members
for member in message.mentions:
await member.add_roles(role)
# Add an reaction after all roles was added
await message.add_reaction("✅")
You should read these articles for more detailed documentation:
message.mentions
guild.get_role
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'm relatively new to programming and am trying to code a bot for a server I'm in. I'd ideally like to assign a user to a specific role based on them sending a message containing 'gm' or 'good morning'. Right now, the bot can read the message and send a reply. But I'm a bit lost trying to figure out how to actually add the role to a user once the 'gm' message is read.
`#client.event
async def on_ready():
print(f'We have logged in as {client.user}')
async def addRole(user : discord.Member, role : discord.Role = BagChaser):
if role in user.roles:
return
else: await user.add_roles(role)
#client.event
async def on_message(message):
if message.author == client.user:
return
msg = message.content.lower()
words_list = ['gm', 'good morning']
if any(word in msg for word in words_list):
# await addRole(message.author, BagChaser)
await message.channel.send(f'Lets get this bag, {message.author}')
await message.author.add_roles(BagChaser)`
the commented line and the last line were some ideas of how to add the role 'BagChaser' to the author of the message. I tried setting the role parameter in the addRole function to BagChaser since that will never change, but this seems incorrect. The role is already made in my server, but I'm not sure how I can make the bot aware of that role in the code. Any help would be greatly appreciated!
I tried explicitly calling out my role but i can't get it recognized.
You need a role object, and to do that, you need a guild object, which you can get with message.author.guild.
From this, you can get the Role object:
role = await message.author.guild.get_role(ROLE_ID)
Note that you need to get the role ID yourself. The easiest method to do so is to go into Discord and enable Developer settings, then right click the role on someone's profile and click "Copy ID". Once you have this role object, you can just apply it with message.author.add_roles(role).
Complete code:
role_id = ...
author = message.author;
role = await author.guild.get_role(role_id)
await author.add_roles(role)
Make sure your bot has the Manage Roles permission
I've been trying to set up a bot that gives a new user who joined my discord server the role "mietzekatze" when he reacts with ":white_check_mark:" to a message. It's like a type of verification or approval. So I found a solution on how to do that, but it does not work. I tried different things, but it won't work. It doesn't return any error, it just wont do, what it's supposed to. Please help, I'm losing my mind.
#client.event
async def on_reaction_add(reaction, member):
Channel = client.get_channel('828667703966433331')
if reaction.message.channel.id != Channel:
return
if reaction.emoji == ":white_check_mark:":
Role = discord.utils.get(member.guild.roles, name="mietzekatze")
await member.add_roles(Role)
I would use a different event here called on_raw_reaction_add. For that you also need payload. You can read the docs for that here.
Re-written your code would look like this:
#client.event
async def on_raw_reaction_add(payload):
guild = client.get_guild(payload.guild_id) # Get the guild
if payload.channel_id == Channel_ID_here: # If the defined channel is correct
if str(payload.emoji) == "✅":
role = get(payload.member.guild.roles, name='mietzekatze') # Or id='RoleID'
else:
role = get(guild.roles, name=payload.emoji)
if role is not None:
await payload.member.add_roles(role) # Add the role
print("Added role") # Check if the role was added
You can use as many if str(payload.emoji) == "YourEmoji": events as you want, just pass them under the other event(s).
Note that you have to pass the ID of a channel/guild without ' '
You have to check for channel's id
if reaction.message.channel.id != Channel.id:
return
When trying to do await member.add_roles(role) where member is a User, it gives me the following error:
'User' object has no attribute 'add_roles'
However, when I look online, there is no mention of such an error, implying that this error isn't supposed to happen.
If it helps, this is the section of the code where this error happens:
#bot.event
async def on_raw_reaction_add(payload):
EMOJI = '✅'
guild = discord.utils.get(bot.guilds, name='The Molehill')
channel = bot.get_channel(740608959207047250)
member = await bot.fetch_user(payload.user_id)
message = await channel.fetch_message(payload.message_id)
MESSAGE = "{user.name} is now part of the Mole Workforce!"
rules_message = message=await channel.fetch_message(740891855666806866)
role = discord.utils.get(guild.roles, name="Worker Mole", id=739514340465705027)
if payload.emoji.name == EMOJI:
if message == rules_message:
await member.add_roles(role)
await bot.send(MESSAGE)
You are trying to add a role to a user object, however they can only be added to member objects. While a user represents a user on discord a member represents a member of a guild.
More information on members in the documentation
A user object is not directly linked with a guild. This is the reason it doesnt have functions to add roles to it. As roles are part of guild functionality.
If we want to fix this we need to get an object that is linked with a guild. The closest match is in this case the member object.
So instead of retrieving the user object and retrieving a member object instead should solve the problem:
#bot.event
async def on_raw_reaction_add(payload):
EMOJI = '✅'
guild = discord.utils.get(bot.guilds, name='The Molehill')
channel = bot.get_channel(740608959207047250)
member = await guild.get_member(payload.user_id)
message = await channel.fetch_message(payload.message_id)
MESSAGE = "{user.name} is now part of the Mole Workforce!"
rules_message = message=await channel.fetch_message(740891855666806866)
role = discord.utils.get(guild.roles, name="Worker Mole", id=739514340465705027)
if payload.emoji.name == EMOJI:
if message == rules_message:
await member.add_roles(role)
await bot.send(MESSAGE)
But when we read the documentation about the on_raw_reaction_add. We see that this can be much more efficient without needing lookups through the bot.
For example in the event documentation you see we get a payload object.
The payload object has the following data (and more just read the documentation):
a member object
guild id
channel id
user id
message id
Notice that we have a member object.
We can retrieve the following from it:
a guild object
So updating the old code to the following increases the performance as we dont need to look up stuff through the bot unnessecarily. Note: I removed some redundant code in this example, I assume you only run this bot in 1 guild, because you are using specific ID's that wont work in other guilds.
#bot.event
async def on_raw_reaction_add(payload):
EMOJI = '✅'
member = payload.member
guild = member.guild
# If you want to run your bot on multiple guilds. Then the code under this comment should be updated.
channel = guild.get_channel(740608959207047250)
MESSAGE = "{user.name} is now part of the Mole Workforce!"
role = guild.get_role(739514340465705027)
if payload.emoji.name == EMOJI:
await member.add_roles(role)
await bot.send(MESSAGE)