So currently I have a discord Bot, and I want to make it welcome any new users in #joining and give them the nickname "[0] Member Name". I'm not getting any errors but neither of these functions are working!
EDIT: Re-Wrote Some Code and I'm Now Getting This Error:
EDIT 2: Still Unable to Edit Nicknames, but when a User Leaves the Server I get these errors from the Function to check if the User is a Staff Member. I don't get errors from the message.author, but when the message author leaves, I start getting this error. I tried resetting the message.author when anyone leaves the server but this didn't help! I don't have any ideas on how to stop these errors!
Ignoring exception in on_message
Traceback (most recent call last):
File "C:\Users\Evan\Anaconda3\envs\testing\lib\site-packages\discord\client.py", line 270, in _run_event
await coro(*args, **kwargs)
File "C:/Users/Evan/PycharmProjects/Bot/bot.py", line 107, in on_message
top_role = message.author.top_role
AttributeError: 'User' object has no attribute 'top_role'
My New Edited Code vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
import discord
import asyncio
import time
# id = 630529690792230923
messages = joined = 0
client = discord.Client()
#client.event
async def on_ready():
print(f'Logged in as: {client.user.name}')
print(f"User ID: {client.user.id}")
print('-----')
async def update_stats():
await client.wait_until_ready()
global messages, joined
while not client.is_closed():
try:
with open("stats.txt", "a") as f:
f.write(f"Time: {int(time.time())}, Messages: {messages}, Members Joined: {joined}\n"),
messages = 0
joined - 0
await asyncio.sleep(3600)
except Exception as e:
print(e)
await asyncio.sleep(3600)
#client.event
async def on_raw_reaction_add(payload):
message_id = payload.message_id
if message_id == 638155786559684608:
guild_id = payload.guild_id
guild = discord.utils.find(lambda g: g.id == guild_id, client.guilds)
if payload.emoji.name == 'Test':
role = discord.utils.get(guild.roles, name='new role')
else:
role = discord.utils.get(guild.roles, name=payload.emoji.name)
if role is not None:
member = discord.utils.find(lambda m: m.id == payload.user_id, guild.members)
if member is not None:
await member.add_roles(role)
print("done")
else:
print("Member Not Found")
#client.event
async def on_raw_reaction_remove(payload):
message_id = payload.message_id
if message_id == 638155786559684608:
guild_id = payload.guild_id
guild = discord.utils.find(lambda g: g.id == guild_id, client.guilds)
if payload.emoji.name == 'Test':
role = discord.utils.get(guild.roles, name='new role')
else:
role = discord.utils.get(guild.roles, name=payload.emoji.name)
if role is not None:
member = discord.utils.find(lambda m: m.id == payload.user_id, guild.members)
if member is not None:
await member.remove_roles(role)
print("done")
#client.event
async def on_member_join(member):
global joined
joined += 1
rule_channel = member.guild.get_channel(channel_id=630530486858547223)
newusermessage = f"""Welcome to CB:NL {member.mention}! Have a Great Time And Make Sure to Look At {rule_channel}"""
channel = member.guild.get_channel(channel_id=630563931412496434)
role = member.guild.get_role(role_id=630533613947060244)
if member is not None:
await member.add_roles(role)
print("done")
await member.edit(str([f"[0] {member.display_name}"]))
await channel.send(newusermessage)
#client.event
async def on_member_remove(member):
discord.message.author = member
#client.event
async def on_message(message):
global messages
messages += 1
id = client.get_guild(630529690792230923)
bad_words = ["test"]
channels = ["bot-commands", "staff-general"]
pn = 1
author = message.author
top_role = message.author.top_role
staff_role = message.author.guild.get_role(role_id=630532857655328768)
if top_role > staff_role:
if message.content.startswith == "-clean":
pass
if str(message.channel) in channels:
if message.content.find("-hello") != -1:
await message.channel.send("Hi")
elif message.content == "-status":
await message.channel.send(f"""# of Members: {id.member_count}""")
else:
if message.author.bot is not 1:
print(f"""{message.author} tried to do command {message.content}""")
await message.channel.send(f"Error, {message.author.mention}. You Cannot Do That!")
client.loop.create_task(update_stats())
I'll respond in answer, because there are multiple mistakes in your code and it's hard to put into the comment. You can comment under this post if you get another error.
role = discord.utils.get(discord.Guild.roles, name="Member")
The error is where you retrieve the role by name Member. It's better to get the role by ID, you can do that using member.guild.get_role(630533613947060244). The error is that discord.Guild.roles is not an iterable property.
nick = discord.utils.get(str(member.nick))
Not sure what is your intention there, you can use nick = member.nick to get a string with member's nickname.
To edit the nickname you should use:
await member.edit(nick=f"[0] {member.display_name}")
AttributeError: 'User' object has no attribute 'top_role'
You get this error because you want to access top_role attribute on instance of discord.User, but only discord.Member has this attribute defined. When someone leaves the server you get the User instance instead of the Member instance.
if isinstance(message.author, discord.Member):
top_role = message.author.top_role
else:
top_role = None # top role not available, user has no roles
Related
Im trying to make a bot that send me a message with a reaction button, when I click it, give me a role in the server. Im trying to use on_raw_reaction_add event but I cant reach a solution to make it, Im always getting errors at getting guild roles and this stuff.
In this case, guild is none, I dont know what Im doing wrong.
My code:
#client.command()
async def test(ctx):
global member
global message__id
global channel_id
channel_id = (ctx.channel.id)
member = ctx.message.author
embed = discord.Embed(title="Verify your account", color=0x03fc14)
embed.add_field(name=f"Verification!", value=('React to this message to get verified!'), inline=False)
embed.set_footer(text=ctx.author, icon_url=ctx.author.avatar_url)
mesg = await member.send(embed=embed)
await mesg.add_reaction("✅")
message__id = mesg.id
print("EXECUTED")
#client.event
async def on_raw_reaction_add(payload):
print("reacted")
print("messageid accepted")
guild = client.get_guild(payload.guild_id)
if guild is not None:
print("messageid accepted")
reactor = payload.guild.get_member(payload.member.id)
role = discord.utils.get(guild.roles, name="Member")
if payload.emoji.name == '✅':
print("emoji accepted")
await reactor.add_roles(role)
EDIT:
I changed my on_raw_reaction_add event:
#client.event
async def on_raw_reaction_add(payload):
print("reacted")
print("messageid accepted")
guild = client.get_guild(payload.guild_id)
if guild is not None:
print("guild not none ")
reactor = payload.guild.get_member(payload.member.id)
role = discord.utils.get(guild.roles, name="Verified")
if payload.emoji.name == '✅':
print("emoji accepted")
await reactor.add_roles(role)
else:
print("guild none")
And this is what happen when I try the method:
First three words are the prints of the bot reacting his own message, the "EXECUTED" is the print of test method and the last three messages. are when I react the bot message
In this case, I suggest using a wait_for rather than on_raw_reaction_add.
Example, as seen in the docs:
#client.command(aliases=["t"])
async def test(ctx):
embed = discord.Embed(title="Verify your account", color=0x03fc14)
embed.add_field(name=f"Verification!", value=('React to this message to get verified!'), inline=False)
embed.set_footer(text=ctx.author, icon_url=ctx.author.avatar_url)
# sends message to command author
mesg = await ctx.author.send(embed=embed)
await mesg.add_reaction("✅")
#check if the reactor is the user and if that reaction is the check mark
def check(reaction, user):
return user == ctx.author and str(reaction.emoji) == '✅'
try:
#wait for the user to react according to the checks
reaction, user = await client.wait_for('reaction_add', timeout=60.0, check=check)
except asyncio.TimeoutError:
# 60 seconds without reaction
await ctx.send('Timed out')
else:
await ctx.send('✅')
docs- https://discordpy.readthedocs.io/en/stable/api.html?highlight=wait_for#discord.Client.wait_for
async def test(ctx):
global member
global message__id
global channel_id
channel_id = (ctx.channel.id)
member = ctx.message.author
embed = discord.Embed(title="Verify your account", color=0x03fc14)
embed.add_field(name=f"Verification!", value=('React to this message to get verified!'), inline=False)
embed.set_footer(text=ctx.author, icon_url=ctx.author.avatar_url)
mesg = await member.send(embed=embed)
await mesg.add_reaction("✅")
message__id = mesg.id
print("EXECUTED")
role = get(ctx.guild.roles, id=role id here)
done = False
while done == False:
reaction, user = await client.wait_for(“reaction_add”, check=check)
if user == client.user:
continue
await member.add_roles(role)
done = True
I am pretty sure something like this would work :D
When you do guild is not None, it will never fire because you are reacting in a DM channel context - where the guild is None. To access the guild information from the DM, you'll need to save it somewhere in the message (or save it yourself internally). Then, you have the guild object and you're able to add roles or do things to it.
#client.command()
async def testrole(ctx):
member = ctx.author
# ...
embed = discord.Embed(title="Verify your account", color=0x03fc14)
embed.add_field(name=f"Verification!", value=('React to this message to get verified!'), inline=False)
embed.set_footer(text=ctx.author, icon_url=ctx.author.avatar_url)
mesg = await member.send(str(ctx.guild.id), embed=embed) # we need the guild information somewhere
await mesg.add_reaction("✅")
#client.event
async def on_reaction_add(reaction, user): # there's really no need to use raw event here
if user.id == client.user.id:
return
if reaction.message.guild is None:
if reaction.emoji == '\u2705':
# we have to get the guild that we saved in the other function
# there is no other way to know the guild, since we're reacting in the DM
# that's why it was saved inside of the message that was sent to the user
guild_id = int(reaction.message.content)
guild = client.get_guild(guild_id)
member = guild.get_member(user.id)
await member.add_roles(...) # change this with your roles
i have a little problem with my code and i don't find any solutions,...
I write a code for my discord bot :
#client.event
async def on_message(message):
if message.content.startswith("!init"):
if message.content.split()[1] == 'règles':
id_channel = 893442599019511829
embed = discord.Embed(title = 'Création bot', description = "par Archi's modo")
embed.add_field(name="Règlement de la LSPD", value="En cliquant sur l'icône ✅ vous reconnaissez avoir blablabla,...")
mess = await client.get_channel(id_channel).send(embed=embed)
await mess.add_reaction('✅')
#client.event
async def on_raw_reaction_add(payload):
id_channel = 893442599019511829
id_message = ?????
role_a_donner = "zabloublou"
message_id = payload.message_id
member = payload.member
if message_id == id_message:
guild_id = payload.guild_id
guild = discord.utils.find(lambda g : g.id == guild_id, client.guilds)
if payload.emoji.name == '✅':
role = discord.utils.get(guild.roles, name=str(role_a_donner))
else:
role = discord.utils.get(guild.role, name=payload.emoji.name)
if role is not None:
if member is not None:
await member.add_roles(role)
channel = client.get_channel(id_channel)
await channel.send(member.mention)
And i don't know how can i get id of the message sended by the bot to use it in my function on_raw_reaction_add
Can someone help me please ?
You should consider using wait_for instead for this kind of use.Your method is mostly used for reaction roles.
Here is an example of wait_for reaction grabbed from discord.py docs for wait_for:
#client.event
async def on_message(message):
if message.content.startswith('$thumb'):
channel = message.channel
await channel.send('Send me that 👍 reaction, mate')
def check(reaction, user):
return user == message.author and str(reaction.emoji) == '👍'
try:
reaction, user = await client.wait_for('reaction_add', timeout=60.0, check=check)
except asyncio.TimeoutError:
await channel.send('👎')
else:
await channel.send('👍')
I try to remove a role using on_raw_rwaction_remove an remove_roles:
Because I don't have the guild_id/member_id in on_raw_reaction_remove I try to get it myself but got this error:
Ignoring exception in on_raw_reaction_remove - AttributeError: 'NoneType' object has no attribute 'request
(and line 45 [guild = await(bot.fetch_guild(payload.guild_id))] causes the error)
Here's the code I'm currently using:
#commands.Cog.listener()
async def on_raw_reaction_remove(self, payload):
ourMessageID = 867876893411508234
if ourMessageID == payload.message_id:
guild = await(bot.fetch_guild(payload.guild_id))
print("fetch successful")
if payload.emoji.name == 'YouTube':
role = discord.utils.get(guild.roles, name="YouTube")
print("Role checked")
elif payload.emoji.name == 'Twitch':
role = discord.utils.get(guild.roles, name="Twitch")
elif payload.emoji.name == 'Discord':
role = discord.utils.get(guild.roles, name="Discord")
elif payload.emoji.name == 'alert':
role = discord.utils.get(guild.roles, name="Community-Events")
member = await(guild.fetch_member(payload.user_id))
print(member)
if member is not None:
await member.remove_roles(role)
else:
print("Member not found")
(I get no response from the two print's)
If I could do something different/simpler, please let me know!
The payload itslef doesn't have guild id but it does have the channel_id, user_id and message_id so you can use the channel id to fetch the channel object and then you can use message id to get the message object and get guild_id from it
#bot.event
async def on_raw_reaction_add(payload):
channel = await bot.fetch_channel(payload.channel_id) # returns channel object
message = await channel.fetch_message(payload.message_id)# returns message object
guild_id = message.guild.id #returns guild id
#REST OF THE CODE
This has worked for me now, thanks for the help:
#commands.Cog.listener()
async def on_raw_reaction_remove(self, payload):
ourMessageID = 867876893411508234
if ourMessageID == payload.message_id:
emoji = payload.emoji.name
guild = await self.bot.fetch_guild(payload.guild_id)
member = await guild.fetch_member(payload.user_id)
#REST OF THE CODE
I get a member not found error when trying to remove a role on reaction remove (on_raw_reaction_remove).
It works to add the role to the member, but it can't remove the role afterwards.
My guess is that it can't properly get the ID for the member, but I don't really know how to fix it.
#client.event
async def on_raw_reaction_add(payload):
message_id = payload.message_id
if message_id == xxxx: #ID depends on message
guild_id = payload.guild_id
guild = discord.utils.find(lambda g : g.id == guild_id, client.guilds)
if payload.emoji.name == 'xxx':
role = discord.utils.get(guild.roles, name="xxx")
elif payload.emoji.name == 'xxxx':
role = discord.utils.get(guild.roles, name="xxx")
else:
role = discord.utils.get(guild.roles, name = payload.emoji.name)
if role is not None:
member = payload.member
if member is not None:
await member.add_roles(role)
print("done")
else:
print("member not found")
else:
print("role not found.")
#client.event
async def on_raw_reaction_remove(payload):
message_id = payload.message_id
if message_id == xxxx: #ID depends on message
guild_id = payload.guild_id
guild = client.get_guild(payload.guild_id)
if payload.emoji.name == 'wexxed':
role = discord.utils.get(guild.roles, name="xxxx")
elif payload.emoji.name == 'xxxx':
role = discord.utils.get(guild.roles, name="xxx")
else:
role = discord.utils.get(guild.roles, name = payload.emoji.name)
if role is not None:
member = guild.get_member(payload.user_id)
if member is not None:
await member.remove_roles(role)
print("done")
else:
print("member not found")
else:
print("role not found.")
payload.member only works with on_raw_reaction_add(), so, instead of using it, you have to fetch the user:
from discord.utils import get
#client.event
async def on_raw_reaction_remove(payload):
guild = await client.fetch_guild(payload.guild_id)
member = get(guild.members, id=payload.user_id)
(...)
PS: If you have discord.py 1.5.0 and didn't set up your Intents, you should look at this answer, or else, your events won't work right.
I am following Anson the Developers tutorial, (here's a link) and I coded exactly as he did, I got no errors, except a warning Parameter 'payload' value is not used and I have made sure that:
The bot has proper permissions to assign roles
The bot is online
The emojis and the roles have the same names
heres the code for reference:
import discord
client = discord.Client()
#client.event
async def on_message(message):
if message.author == client.user:
return
#client.event
async def on_raw_reaction_add(payload):
message_id = payload.message_id
if message_id == '756794977148993597':
guild_id = payload.guild_id
guild = discord.utils.find(lambda g: g.id == guild_id, client.guilds)
role = discord.utils.get(guild.roles, name=payload.emoji.name)
if role is not None:
member = discord.utils.find(lambda m: m.id == payload.user_id, guild.members)
if member is not None:
await member.add_roles(role)
print("done")
else:
print("member not found")
else:
print("role not found")
client.run('REDACTED')
I have tried a lot of troubleshooting and any help would be appreciated!
You should not use utils.find in your case.
client.get_guild to get the guild by id.
guild.get_member to get the member by id. also you can use guild.get_member_named if you want to use a name.
#client.event
async def on_raw_reaction_add(payload):
if payload.message_id == 756794977148993597:
guild = client.get_guild(payload.guild_id)
role = discord.utils.get(guild.roles, name=payload.emoji.name)
if role is not None:
member = guild.get_member(payload.user_id)
if member is not None:
await member.add_roles(role)
print("done")
else:
print("member not found")
else:
print("role not found")