I am trying to remove a role when a reaction is removed. I already have the 'add reaction' roles that work perfectly. However, whenever I try to run this, it ends up printing "removed None" (none as the role) which means it doesn't remove the role. I think it has something to do with getting the roles. Here is the code:
#commands.Cog.listener()
async def on_raw_reaction_remove(self, payload):
messageID=962844879044628510
if messageID== payload.message_id:
guild= self.bot.get_guild(payload.guild_id)
member = guild.get_member (payload.user_id)
if str(payload.emoji) == "<a:black_drip:961304023401652274>":
role = get(payload.member.guild.roles, name='evnt')
elif str(payload.emoji) == "<a:Uzi_spin:962831415114879056>":
role = get(guild.roles, name='chat revive')
elif str(payload.emoji) == "<a:BlackFire:934621316298964992>":
role = get(guild.roles, name='gw')
elif str(payload.emoji) == "<a:Black_LV:961428631803027466>":
role = get(guild.roles, name='vc')
else:
role = discord.utils.get(guild.roles, name=payload.emoji)
if role is not None:
await payload.member.remove_roles(role)
print(f"Removed {role} from {member}.")
Raw reaction events return PartialEmoji. Never rely on the rendering behavior. You can compare them by using their IDs, such as my_part_emoji.id == 123456.
Also, using raw events may not be a good idea - you need access to the messages. It would be better to use the normal reaction event instead.
Related
I'm trying to get it so a specific role can react to the message to be able to ban the user, I have made the ability to be able to react to the message, and the author of the command can ban the user, but I want to make it so another role can do it as well
Here is what I have currently
def check(rctn, user):
return user.id == ctx.author.id and str(rctn) == '<:tick:837398197931868190>'
reaction, user = await bot.wait_for('reaction_add', check=check)
You can use #commands.has_permissions
For example you could make it:
#bot.command()
#commands.has_permissions(ban_members=True)
# rest of your code
This way only roles with the permissions to ban_members can use the command
I have been making a discord bot and tried making commands that use reactions. I have seen that using wait_for is the best way of achieving exacly that. If anyone could provide some examples for:
• Using reactions to give roles
• Using reactions to create a channel
• Using reactions to edit a message
If you could break down the code line by line so i could learn it instead if just copy pasting, it would be greatly appreciated. Thank you in advance
The documentation has an great explanation but can be difficult to understand at first,
usually reaction roles is done like this (if we leave databases out for now):
reaction, user = await self.bot.wait_for('reaction')
if str(reaction.emoji) == '👍':
role = discord.utils.get(ctx.guild.roles, name='thumbsup')
await user.add_roles(role)
elif str(reaction.emoji) == '👎':
role = discord.utils.get(ctx.guild.roles, name='thumbsdown')
await user.add_roles(role)
but this code can be optimized like this, it also simulates a database:
reaction, user = await self.bot.wait_for('reaction')
roles = {'👍': 'thumbsup', '👎': 'thumbsdown'}
role = discord.utils.get(ctx.guild.roles, name=roles[str(reaction.emoji)])
await user.add_roles(role)
This is what i generally use as it implements checks
message = ctx.send("message")
reactions = [...]
def check(r:discord.reaction, u:discord.user):
checker = message.id == reaction.message.id
checker = checker and u == message.author
checker = checker and r in reactions
return checker
while true:
reaction, user = await self.bot.wait_for("reaction_add",check=check)
if reaction == reactions[0]:
ctx.send("reaction one")
elif reaction == reactions[1]:
ctx.send("reaction two")
elif reaction == reactions[2]:
break
If you want you can also have a list of users that can react and in the check check if the user is in users
in discord you can do member == user
I want to use regex to look at and accept literally ANY incoming message from a user and assign them a role. But ONLY if that user does not have a role already assigned to them. I don't get any errors when running the code, but it does not work.
Here is what I have:
#client.event
async def on_message(message):
match = re.search(r'(.*?)', message.content)
member = message.author
role = discord.utils.get(member.guild.roles, name="Creators")
if message.author == client.user:
return
if role not in member.roles:
if match and message.channel.id == target_channel:
# add member to role
# send message to to users
await message.channel.send(
f'Hi {message.author}, welcome to the server! Don\'t forget to choose your #roles'
)
await discord.Member.add_roles(member, role)
You wrote:
await discord.Member.add_roles(member, role)
https://discordpy.readthedocs.io/en/latest/api.html?highlight=add_role#discord.Member.add_roles
As you can see from the documentation the passed arguments is *roles, reason=None, atomic=True. roles is something you have to specify, reason and atomic are optional.
You tried passing member which is not a valid argument.
discord.Member is a class. You need to get an instance of that class. ctx.author is an instance of discord.Member.
So the final call should be:
await ctx.author.add_roles(role)
To get the Member object from on_message, you can use member = message.author.
Then simply do member.add_roles(role).
Thanks for the help guys, it turns out it was something very minor (and dumb on my part) that prevented it from working.
when comparing message.channel.id.id to target_channel, I forgot that the channel id object does not come in as a string, but target_channel was set up as a string, so it failed to see them as equal. Simply converting message.channel.id to string did the trick.
So modern documentation on the bot.wait_for() coroutine is not super detailed, and I'm having trouble getting it to work with reactions. Would appreciate feedback.
Python 3 with Discord.py
## Test Role Add
#kelutralBot.command(name='testreaction')
async def testReaction(ctx):
member = ctx.message.author
message = await ctx.send("This is a test message.")
emojis = ['\u2642','\u2640','\u2716']
for emoji in emojis:
await message.add_reaction(emoji)
def check(reaction, user):
return user == message.author and str(reaction.emoji) == '\u2642'
try:
reaction, user = await kelutral.wait_for('reaction_add', timeout=60.0, check=check)
except asyncio.TimeoutError:
await ctx.send("Window has passed to self-assign pronouns. Please DM a mod if you would still like to do so.")
else:
print(reaction)
male = get(member.guild.roles, name="He/Him")
await member.add_roles(male)
print("Assigned " + member.name + " He/Him pronouns.")
Two things were wrong.
First, don't use Client and Bot in the same command. Bot is sufficient for both.
Second, Unicode Emoji for Discord are treated as '\U000#####', which was the biggest problem.
Once we solved that, everything worked as intended.
The problem here is that you are checking if the person who sent the reaction is the author of the message that contains the message, which is only satisfied by the bot that reacted. Also consider using a role ID instead (server settings > roles > left click role > right click role > copy ID). You also want to be consistent with kelutral or kelutral Bot throughout the command.
#kelutralBot.command(name='testreaction')
async def testReaction(ctx):
member = ctx.message.author
message = await ctx.send("This is a test message.")
emojis = ['\u2642','\u2640','\u2716']
for emoji in emojis:
await message.add_reaction(emoji)
def check(reaction, user):
return user == member and str(reaction.emoji) == '\u2642' # check against the member who sent the command, not the author of the message
try:
reaction, user = await kelutralBot.wait_for('reaction_add', timeout=60.0, check=check)
except asyncio.TimeoutError:
await ctx.send("Window has passed to self-assign pronouns. Please DM a mod if you would still like to do so.")
else:
print(reaction)
male = ctx.message.guild.get_role(ROLE_ID_GOES_HERE) # put your role ID here #
await member.add_roles(male)
print(f"Assigned {member.name} He/Him pronouns.")
Keep in mind your code only works for the "male" role, you have to implement a different check function to use it for everything.
I have an issue with assigning roles to discord users in my server with the bot i created.
The code I made is for interacting with FaceIT, which works fine, but I want to be able to assign roles based on how many matches have been played by a user.
With my Code, I know the IDs of the discord user as they are stored in a config file, and the config is loaded into an array called server_config
When I run the code, I get this error:
discord.ext.commands.errors.CommandInvokeError: Command raised an exception: AttributeError: 'Guild' object has no attribute 'add_roles'
Here is a sniplet of my code below
#client.command(aliases=["lvl"])
async def assignLvl(ctx):
global server_config
players = server_config[str(ctx.guild.id)]['players']
# Making sure the server is registered
check_server(ctx)
.
.
. this part gets FACEIT data and works
.
.
.
gzk_srvr = ctx.guild
for item in hub_data:
for key in players:
if players[key] == item['nickname']:
if int(item['stats']['Matches']) >= 1 and int(item['stats']['Matches']) < 5:
role = get(gzk_srvr.roles, name="First Scrim Attendee")
user = gzk_srvr.get_member(int(key))
await gzk_srvr.add_roles(players[key], role)
if int(item['stats']['Matches']) >= 5 and int(item['stats']['Matches']) < 15:
role = get(gzk_srvr.roles, name="Lvl 1 Scrimmer")
user = gzk_srvr.get_member(int(key))
await gzk_srvr.add_roles(players[key], role)
if int(item['stats']['Matches']) >= 15 and int(item['stats']['Matches']) < 30:
role = get(gzk_srvr.roles, name="Lvl 2 Scrimmer")
user = gzk_srvr.get_member(int(key))
await gzk_srvr.add_roles(players[key], role)
if int(item['stats']['Matches']) >= 30:
role = get(gzk_srvr.roles, name="Lvl 3 Scrimmer")
user = gzk_srvr.get_member(int(key))
await gzk_srvr.add_roles(players[key], role)
I've seen a few questions and answers on this, and tried implementing them, for example where the OP's answer would be to use await client.add_roles(.....) but i would also get a similar exception thrown
like Bot has no attribute add_roles
I appreciate any help I can get to point me in the right direction.
You need to add the role to the member. To get the Guild's roles, you can use discord.utils.get.
await member.add_roles(discord.utils.get(gzk_srvr.roles, name="Role Name"))