How do I define a member inside a on_raw_reaction_remove()? - discord.py

I tried to write a code that will remove a role from a member when a certain reaction is added. My code works fine until the end, where the role is removed from the member, where an "Attribute error" pops up; "AttributeError: 'NoneType' object has no attribute 'remove_roles'"
Here's my code:
#client.event
async def on_raw_reaction_remove(payload):
await client.wait_until_ready()
guild = await client.fetch_guild(payload.guild_id)
member = get(guild.members, id=payload.user_id)
if payload.message_id == id:
if payload.emoji.name == "a":
role = discord.utils.get(guild.roles, name = "a")
elif payload.emoji.name == "b":
role = discord.utils.get(guild.roles, name = "b")
await member.remove_roles(role)
My guess is that i'm defining member the wrong way, but I have no idea how to fix it

In this situation client.get_user() works better.
Here is the fixed code
#client.event
async def on_raw_reaction_remove(payload):
await client.wait_until_ready()
guild = await client.fetch_guild(payload.guild_id)
member = client.get_user(id=payload.user_id)
if payload.message_id == id:
if payload.emoji.name == "a":
role = discord.utils.get(guild.roles, name = "a")
elif payload.emoji.name == "b":
role = discord.utils.get(guild.roles, name = "b")
await member.remove_roles(role)
Hope this helped!

The main reason behind this is payload.member is None when using on_raw_reaction_remove.
This is actually because discord does not send this data, so discord.py has it as None.
Source-https://github.com/Rapptz/discord.py/issues/5871
To work around this, you get the guild object in question, then grab the member object from the guild.
The payload does not have the guild object either, so we have to get that as well.
What I did is I actually created the member object and tacked it onto the payload manually in the case of on_raw_reaction_remove.
This way both on_raw_reaction_add and on_raw_reaction_remove have the same payload for my final processing.
async def on_raw_reaction_remove(self, payload):
guild = self.get_guild(payload.guild_id) #Self here is Client/Bot
member = guild.get_member(payload.user_id)
payload.member = member
await reaction_role(payload, remove=True)
Furthermore, this requires the privileged members intent. To enable it, log back into the developer portal and look for the privileged intents > member intent, then tick the slider to on.
intent = discord.Intents.default()
intent.members = True
The intent needs to be passed to the client, or bot wrapper if using the bot extension.
commands.Bot.__init__(self, <...>, intents=intent)

Related

How to add and remove role from users using ID

I'm trying to create a command which allows users with the role Recruiter to promote tryout to soldier, I'm using arg1 as the mentioned user and then striping that down to get just the ID, but i cant add the roles since it keeps saying `str` object has no attriubute `add_roles`
#bot.command(name="promote", aliases = ["p"])
#commands.has_role('Recruiter')
async def _promote(self , ctx: commands.Context , arg1):
"""Promotes a tryout to recruit"""
guild = ctx.guild
tryout = ctx.guild.get_role(976813881232085052)
soldier = ctx.guild.get_role(973765272106332211)
userid = arg1.strip("<>#!")
await userid.add_roles(soldier)
await userid.remove_roles(tryout)
await ctx.send("Successfull")
You really need to read about this library converters and make your life easier;
But in a nutshell typehinting member: discord.Member will actually try to convert string you say in discord to discord.Member object so for example
!promote #Alex, !promote Alex, !promote 1234567 (alex id) will put Alex into member argument as discord.Member (which can be used for add/remove_roles) and raise commands.MemberNotFound if none member could be found.
#bot.command(name="promote", aliases=["p"])
#commands.has_role('Recruiter')
async def _promote(self, ctx: commands.Context, member: discord.Member):
"""Promotes a tryout to recruit"""
tryout = ctx.guild.get_role(976813881232085052)
soldier = ctx.guild.get_role(973765272106332211)
await member.add_roles(soldier)
await member.remove_roles(tryout)
await ctx.send("Successfull")

Discord.py Reaction Roles with Embed dont work

Im Trying to make a discord bot which sends an embed message with a reaction, and if a user reacts to that message he/she would get a role. This is for the Rules of the Server.
The Problem is, the Embed message gets sent but there is no reaction. If I manually react to it, and get someone else to react too he/she will get no role. (The embed message is the only message in that channel). I also get no Errors in the console.
The 'channel_id_will_be_here' is always replaced with the correct channel Id.
Thank you.
import discord
from discord.ext import commands
client = discord.Client()
#client.event
async def on_ready():
Channel = client.get_channel('channel_id_will_be_here')
print("Ready as always chief")
#client.event
async def on_message(message):
if message.content.find("|rules12345654323") != -1:
embedVar = discord.Embed(title="**Rules**", description="The Rules Everybody needs to follow.", colour=discord.Colour.from_rgb(236, 62, 17))
embedVar.add_field(name="Rule 1", value="Be nice etc", inline=False)
await message.channel.send(embed=embedVar)
async def on_reaction_add(reaction, user):
Channel = client.get_channel('channel_id_will_be_here')
if reaction.message.channel.id != Channel:
return
if reaction.emoji == ":white_check_mark:":
Role = discord.utils.get(user.server.roles, name="Player")
await client.add_roles(user, Role)
In if reaction.message.channel.id != Channel you compare the id to the Channel object, not the Channel.id.
You don't need to use the object there, just the id (which you use to create the channel object in the first place) would be fine
if reaction.message.channel.id != channel_id_will_be_here:
return
You could also use the message id like(So it'll only trigger when reacting to that exact message):
if reaction.message.id != rules_message_id_will_be_here:
return
The way you do your check is pretty strange too, why check to make the function return if False? Why not just make it add the role when True?
async def on_reaction_add(reaction, user):
if reaction.message.channel.id == channel_id_will_be_here and reaction.emoji == ":white_check_mark:":
Role = discord.utils.get(user.server.roles, name="Player")
await client.add_roles(user, Role)
You could even leave out the if reaction.emoji == ":white_check_mark:": part if it is the only message/emote reaction in that channel

Discord.py adding a role through reactions

I am using code that I found here.
But, I'm getting an error that the client object doesn't have the attribute send_message. I have tried message.channel.send but that failed as well.
#client.event
async def on_ready():
Channel = client.get_channel('YOUR_CHANNEL_ID')
Text= "YOUR_MESSAGE_HERE"
Moji = await client.send_message(Channel, Text)
await client.add_reaction(Moji, emoji='🏃')
#client.event
async def on_reaction_add(reaction, user):
Channel = client.get_channel('YOUR_CHANNEL_ID')
if reaction.message.channel.id != Channel:
return
if reaction.emoji == "🏃":
Role = discord.utils.get(user.server.roles, name="YOUR_ROLE_NAME_HERE")
await client.add_roles(user, Role)
One of the reasons why your code might not be working is because you may have your channel id stored in a string. Your code shows:
Channel = client.get_channel('YOUR CHANNEL ID')
The code above shows that your channel id is stored in a string, which it should not be. With the code above, your actual code may look like this:
Channel = client.get_channel('1234567890')
Instead you should have:
Channel = client.get_channel(1234567890)

Role delete and Role remove commands are not working | Discord.py

I made a role remove and role delete command that, idk what happened to it. It was working fine but the bot doesn't respond neither does it remove/delete the role. I might have messed it up while working on other commands, since everything else works fine but when I searched up online solutions. All the results were the same as my code. Not sure what's happening.
Role delete command:
#commands.command()
async def roledelete(self, ctx, *, role: discord.Role):
await role.delete()
await ctx.send(f'"{role}" got yeeted')
Role remove command:
#commands.command()
async def roleremove(self, ctx, roles, member: discord.Member=None):
if member == None:
member = ctx.message.author
guild = ctx.guild
role = discord.utils.get(guild.roles, name=f"{roles}")
await member.remove_roles(role)
await ctx.send(f"{roles} role has been removed")
For roleremove, you are running the code to remove a role from a member if member == None. If a member is specified there is no code to remove the role from the user. This should fix that
#commands.command()
async def roleremove(self, ctx, roles, member: discord.Member=None):
if member == None:
pass
else:
member = ctx.message.author
guild = ctx.guild
role = discord.utils.get(guild.roles, name=f"{roles}")
await member.remove_roles(role)
await ctx.send(f"{roles} role has been removed")
There is no problem in roledelete so the issue must be elsewhere in your code.
the question was only meant for remove not delete command lol. Anyways, so I removed a variable and replaced some of the code on my remove command and it worked. I spent a whole day trynna figure out how to do this and the solution was as simple as this lol. Here's the code if anyone needs it:
#commands.command()
async def roleremove(self, ctx, roles, member: discord.Member=None):
role = discord.utils.get(ctx.guild.roles, name=f"{roles}")
await member.remove_roles(role)
await ctx.send(f"{roles} role has been removed")
if member == None:
await ctx.send("Ok I'll remove roles but from who tho??"

How to make a discord.py reaction role code

I'm new to discord bot making, and I'd like to have the bot add a reaction to my message that, once pressed, allows the user reacting to pick up a role. What would be the code to allow me to do this? Thank you.
This is a very well written and formatted question! In order for the bot to detect that the reaction is on a specific message, you can do many ways. The easiest way would be to be by ID, so I'm just going to do this with a simple command.
messageIDs = []
#client.event
async def on_raw_reaction_add(payload):
global messageIDs
for messageID in messageIDs:
if messageID == payload.message_id:
user = payload.member
role = "roleName"
await user.add_roles(discord.utils.get(user.guild.roles, name = role))
#client.command()
async def addMessage(ctx, messageID):
global messageIDs
emoji = "👍"
channel = ctx.message.channel
try:
msg = await channel.fetch_message(messageID)
except:
await ctx.send("Invalid Message ID!")
return
await msg.add_reaction(emoji)
messageIDs.append(messageID)

Resources