'User' object has no attribute 'add_roles' - python

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)

Related

How to check if the player has a role when the bot starts and sends the message "on_ready"

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

How do I remove roles from a user?

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.

Discord.py guild invite bot

If the code is correct, I want to make a bot where the bot invites me to a specific server.
but it has error.
Here's my code:
#client.command()
async def invite(ctx, *, code):
if code == "12320001":
guild = "851841115896152084"
invite = await ctx.guild.create_invite(max_uses=1)
await ctx.send(f"Here's your invite : {invite}")
else:
await ctx.send(f"Code is wrong!")
and error:
discord.ext.commands.errors.CommandInvokeError: Command raised an exception: AttributeError: 'NoneType' object has no attribute 'create_invite'
ctx.guild is None, that is why you are getting this Exception.
You can check the value of ctx.guild before passing ctx as a parameter while calling invite function.
As the error suggests, ctx.guild is None. This usually occurs when invoking a command in a DM rather than in a server, as there obviously is no server in DMs.
Judging by the fact that you have a guild variable that you never used I assume that you're trying to invite people to that guild instead.
# Make sure the id is an int, NOT a string
guild = client.get_guild(85184111589615208)
# Invite users to the guild with the above id instead
invite = await guild.create_invite(max_uses=1)
You need a Channel object to create an invite as the Guild class doesn't have a create_invite() method. You can the code given below. Note that the server should have at least one channel.
#client.command()
async def invite(ctx, code):
if code == "12320001":
guild = client.get_guild(851841115896152084)
invite = await guild.channels[0].create_invite(max_uses = 1)
await ctx.send(f"Here's your invite: {invite}")
else:
await ctx.send("Invalid code!")

Issue with giving roles with a command Discord Py

I have made a command to set someone ROLE, However, it's throwing errors.
Command raised an exception: AttributeError: 'str' object has no attribute 'add_roles'
Is there anything wrong I have did? I am using the latest discord py version.
#bot.command()
async def set_role(ctx,member = None,val: int = None):
ab = member
ab = ab.replace("<","")
ab = ab.replace(">","")
ab = ab.replace("#","")
ab = ab.replace("!","")
user = bot.get_user(int(ab))
if val == 1:
role = discord.utils.get(ctx.guild.roles, name="Test")
await user.add_roles(role)
await ctx.send('Updated')
user = bot.get_user(int(ab))
This creates a user object. It is not affiliated to a guild / discord server. By design you cannot do add_roles.
Reason being your bot might not share a guild with this user. Or your bot might share multiple guilds with this user. But how does it know which guild you are actually adressing?
You need to create a member object. This could be done with:
member = ctx.guild.get_member(int(ab))
Now you have a member object and you can await add_roles.
await member.add_roles(role)
https://discordpy.readthedocs.io/en/latest/api.html#discord.Member.add_roles
to give a role to a member u need to give the member and the name of the role as inputs.
for example:
" ?set_role #clay#9871 example "
the bot gonna search for a role name 'example' from the guild roles
if the bot didn't find the role it will send "role not found" that's what the "try" and "except" for
#bot.command()
async def set_role(ctx,member :discord.Member,role):
try:
add_role= discord.utils.get(ctx.guild.roles, name=role)
await member.add_roles(add_role)
await ctx.send('Updated')
except:
await ctx.send("role not found!")

Discord.py rewrite - looking to see if a member is server muted, no info found on API Reference

How do I go about looking to see if a Member object is server muted? I can use the edit() function to mute them, but I want to retrieve a list of all members of a server that are muted. But I can't do that if I can't make a check to see if the Member object is muted.
Also how do I change a user's permission so they can't send messages (a mute function)
if ctx.author.is_muted(): # <<< Goal :) Not a real function
await ctx.author.edit(mute=False) # Is a real function, only works on voice connection.
else:
pass
As you said (and as I know), there is no way to mute a server member properly using a function that is provided by the discord.py API. You can mute a member in the voice chat but not in text channels.
The only way to avoid a user to send messages is to create a mute role and change all the channels perms.
Here are some examples of what you can do to answer your question :
Mute role :
So we wan't to create a role called "muted" if it doesn't exist each time we call the command mute #user :
import discord, asyncio
from discord.utils import get
async def create_mute_role(guild):
'''
`guild` : must be :class:`discord.Guild`
'''
role_name = "muted"
mute_role = get(guild.roles, name = role_name) # allows us to check if the role exists or not
# if the role doesn't exist, we create it
if mute_role is None:
await guild.create_role(name = role_name)
mute_role = get(guild.roles, name = role_name) # retrieves the created role
# set channels permissions
for channel in guild.text_channels:
await asyncio.sleep(0)
mute_permissions = discord.PermissionsOverwrite()
mute_permissions.send_messages = False
await channel.set_permissions(mute_role, overwrite = mute_permissions)
return(mute_role)
Your mute #user command will do something like :
#commands.command()
async def mute(self, ctx, member: discord.Member):
guild = ctx.message.guild
mute_role = await create_mute_role(guild)
await member.add_roles(mute_role)
await ctx.send(f"{member.name} has been muted !")
return
Get the muted members :
To get a list of your server muted members, you want to use role.members.
So doing :
muted_list = mute_role.members
print(len(muted_list))
Will display the amount of muted members, you can walk through this list with :
for member in muted_list:
Hope it helped !

Categories