Discord Python: Adding a role to a member - python

My bot checks whenever a user is added to a guild on Discord and then privately DMs them for their email address. It then sends a one-time code to the email address and asks the user to enter the code in the DM. All this is implemented and works. However, when the user answers with the code, I cannot seems to be able to assign a new role to the user. Here is what I currently have (I removed the code that checks the one-time code, etc. as it works and does not seem to be the source of the problem):
import discord
from discord.ext import commands
from discord.utils import get
#client.event
async def on_message(message):
# Check if message was sent by the bot
if message.author == client.user:
return
# Check if the message was a DM
if message.channel.type != discord.ChannelType.private:
return
user_code = 'some code sent via email'
if message.content == user_code:
member = message.author
new_guild = client.get_guild(int(GUILD_ID))
role = get(new_guild.roles, id=DISCORD_ROLE)
await member.add_roles(role)
response = "You can now use the Discord Server."
await message.channel.send(response)
Here is the error I receive:
Traceback (most recent call last):
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/discord/client.py", line 312, in _run_event
await coro(*args, **kwargs)
File "main.py", line 89, in on_message
await member.add_roles(role)
AttributeError: 'User' object has no attribute 'add_roles'

For that, you need to transform the User object into a Member object. That way, you can call the add_roles method. Here is one way of doing it:
import discord
from discord.ext import commands
from discord.utils import get
#client.event
async def on_message(message):
# Check if message was sent by the bot
if message.author == client.user:
return
# Check if the message was a DM
if message.channel.type != discord.ChannelType.private:
return
user_code = "some code sent via email"
if message.content == user_code:
new_guild = client.get_guild(int(GUILD_ID))
member = new_guild.get_member(message.author.id)
role = new_guild.get_role(int(DISCORD_ROLE))
await member.add_roles(role)
response = "You can now use the Discord Server."
await message.channel.send(response)

Related

error with discord.py NoneType object has no attribute 'id'

Ok, so I try to make a command with on_message, I put await bot.process_commands(message). But it always raises the 'NoneType' object has no attribute 'id'.
import os
import random
import discord
from discord.ext import commands
from dotenv import load_dotenv
load_dotenv()
TOKEN = os.getenv('DISCORD_TOKEN')
intents = discord.Intents.default()
intents.message_content = True
activity = discord.Activity(name='null, dying, trying to fix me', type=discord.ActivityType.watching)
client = discord.Client(intents=intents, activity = activity)
bot = commands.Bot(intents=intents,command_prefix='!')
#client.event
async def on_ready():
print(f'{client.user.name} has connected to Discord!')
channel = client.get_channel(956302622170701946)
await channel.send(f'connected successfully as {client.user.name}#{client.user.discriminator}')
#client.event
async def on_message(message):
await bot.process_commands(message)
if message.author == client.user:
return
if message.content.startswith('hello'):
await message.channel.send("hello stopid")
elif message.content.startswith('die'):
await message.channel.send('ok :sob: i ded now')
await client.close()
#bot.command
async def a(ctx):
await ctx.send("a")
client.run(TOKEN)
this is the entire error:
2022-12-08 18:15:54 ERROR discord.client Ignoring exception in on_message
Traceback (most recent call last):
File "C:\Users\xxxxx\source\repos\DBot\DiscordBot\lib\site-packages\discord\client.py", line 409, in _run_event
await coro(*args, **kwargs)
File "c:\Users\xxxxx\source\repos\DBot\discordbot.py", line 25, in on_message
await bot.process_commands(message)
File "C:\Users\xxxxx\source\repos\DBot\DiscordBot\lib\site-packages\discord\ext\commands\bot.py", line 1389, in process_commands
ctx = await self.get_context(message)
File "C:\Users\xxxxx\source\repos\DBot\DiscordBot\lib\site-packages\discord\ext\commands\bot.py", line 1285, in get_context
if origin.author.id == self.user.id: # type: ignore
AttributeError: 'NoneType' object has no attribute 'id'
i just want a command with the prefix '$' and sends back the args sent by the user
i probably did something stupid but still thanks.
You only need the bot instance, client is unnecessary. CommandsBot is just upgraded discord.Client and also includes the #bot.event decorator
remove client.close() and move bot.process_commands(message) to the bottom of your on_message function
*Note you should not be doing anything else than prints in on_ready since that fires multiple times

What's wrong with my discordpy get() method?

So I want to write a funny little discord bot that's in a russian theme. I want to make it play the USSR Anthem no matter what song is requested, in the channel that's written after "&channel" in the command on discord.
This is the console feed I get, when I type "vadim play something &channel Just Chatting blyat:
Privet
Just Chatting
Ignoring exception in on_menter code hereessage
Traceback (most recent call last):
File "C:\Users\maria\AppData\Local\Programs\Python\Python39\lib\site-packages\discord\client.py", line 343, in _run_event
await coro(*args, **kwargs)
File "C:\Users\maria\Desktop\Coding\Projekte\Python\SovjetBot\Code\bot.py", line 33, in on_message
voicechannel = channel.connect()
AttributeError: 'NoneType' object has no attribute 'connect'
Here's my code:
import discord
from discord.utils import get
import time
class MyClient(discord.Client):
#Triggered on login
async def on_ready(self):
print("Privet")
#Triggered on messages
async def on_message(self, message):
if message.author == client.user:
return
if message.content.lower().startswith("vadim") and message.content.lower().endswith("blyat"):
messagearray = message.content.split(" ")
messagearray.pop()
messagearray.remove("vadim")
if messagearray[0].lower() == "play" and ((len(messagearray)) != 1 or messagearray.contains('&channel')):
where = ""
for i in range(messagearray.index("&channel") + 1, len(messagearray)):
where = where + ' ' + messagearray[i]
where = where[0:]
time.sleep(0.25)
print(where)
channel = get(message.guild.channels, name=where)
time.sleep(0.25)
voicechannel = channel.connect()
time.sleep(0.25)
voicechannel.play(discord.FFmpegPCMAudio('National Anthem of USSR.mp3'))
client = MyClient()
client.run(The bots client id)
TLDR
Change
channel = get(message.guild.channels, name=where)
To
channel = await get(message.guild.channels, name=where)
Explanation
There error indicates you have an issue on the line voicechannel = channel.connect() because channel is NoneType. You define channel on the line above with channel = get(message.guild.channels, name=where). However, according to the documentation the get() function you're using is a coroutine so you need to await it.
Side Note
After you create channel, you should check that it's not None before you try to use it with voicechannel = channel.connect().

Discord.py - How to get A's ID from B's message when B is sending a message that is replying to A's original message?

I'm trying to make a discord bot to automate playing my friend's bot's game. When my friend's bot sends a message replying to your message after you use a specific command. I want to be able to check if the message the bot sends is replying to my message specifically. This is what I've got so far:
#bot.event
async def on_message(message):
if message.author.id == botId:
content = str(message.content)
reference = message.reference
if reference.message_id.author.id == myId:
word = content.split('`')[1].split('`')[0]
await bot.send_message(message.channel, word)
I know reference.message_id.author.id will not work since author.id is incompatible with reference.message_id, but I cannot find something that will work with it.
The Error:
Ignoring exception in on_message
Traceback (most recent call last):
File "C:\Users\user\AppData\Local\Programs\Python\Python39\lib\site-packages\discord\client.py", line 343, in _run_event
await coro(*args, **kwargs)
File "C:\Users\user\OneDrive\Desktop\User\Projects\Programming\Python\Discord Bot\Waterhole Dryer\bot.py", line 30, in on_message
if reference.message_id.author.id == myId:
AttributeError: 'int' object has no attribute 'author'
Thanks!
Alrighty, so... I found a bit of a workaround to this...
#bot.event
async def on_message(message):
if message.author.id == botId:
guild = bot.get_guild(guildId)
channel = guild.get_channel(message.reference.channel_id)
msg = await channel.fetch_message(message.reference.message_id)
if msg.author.id == myId:
word = content.split('`')[1].split('`')[0]
await channel.send(word)
Basically, I made a new message object. I hope this helps anyone else with my problem.

Only send welcome DM to users of specific server in discord.py

I have a discord bot who resides in multiple servers, however I would like to either have join messages for each server or ensure my bot only sends the welcome message to those joining one of them.
#client.event #Send new members of the server a message
async def on_member_join(member): #Run when a member joins
await member.create_dm() #Create a DM chat with the new user
await member.dm_channel.send(f"Heya, {member.name}! [ETC OF WELCOME MESSAGE]")
print(f'User DM sent:\n----------\nUser: {member.name}\n----------')
According to the documentation, the only parameter of on_member_join is member, so is this not possible?
I have been attempting to send the DM based on server IDs.
After some research, I saw ctx.author.send, but that didn't work:
File "REDACTED", line 312, in _run_event
await coro(*args, **kwargs)
File "REDACTED", line 34, in on_member_join
await ctx.author.send(f"Heya, {member.name}! REDACTED")
AttributeError: 'Member' object has no attribute 'author'
Here is the full code, in its current form.
#client.event
async def on_member_join(ctx):
current_server = ctx.guild.id
if current_server == server_id:
await ctx.author.send(f"Heya, {member.name}! REDACTED")
print(f'User DM sent:\n----------\nUser: {member.name}\n----------')
The docs here provide the signature for on_member_join event. So you can use member object provided by the event to get the id of server joined and compare it against stored guild id.
For a single server:
# stored_guild_id must be defined before this code appears
#client.event
async def on_member_join(member: discord.Member):
if member.guild.id == stored_guild_id:
await member.send(f"Welcome to the server!")
If you have a bunch of servers you can use a list of servers:
# stored_guild_ids must be defined above this code. For example:
# stored_guild_ids = [id1, id2]
# where id1 and id2 are guild ids
#client.event
async def on_member_join(member: discord.Member):
if member.guild.id in stored_guild_ids:
await member.send(f"Welcome to the server!")
You can also store it as a dictionary and have separate greeting for each server.
# welcome_messages must be defined. For example:
# welcome_messages = {
# guild_id: "Welcome there!",
# guild_id2: 'Hello there!'
# }
# Again guild_id and guild_id2 are actual guild ids
#client.event
async def on_member_join(member: discord.Member):
if member.guild.id in welcome_messages.keys():
await member.send(welcome_messages[member.guild.id])
Depending on the use case this might also be extended to store welcome messages in files and have a command to edit welcome messages from discord using a command. You can also set message to have a field such as:
welcome_messages = {my_guild_id: "Hello {0}! Welcome to server")
and use
await member.send(welcome_messages[guild_id].format(member.mention))
which would replace 0 with mention of new user.

Discord.py Module Python 3.6.4 kick feature

I was making a discord bot using the discord module in python... I am having a lot of trouble trying to make the kick command work. I tried using bot.kick, client.kick and ctx.kick but they all give the same error which says,
Ignoring exception in command kick:
Traceback (most recent call last):
File "C:\Users\user\AppData\Roaming\Python\Python36\site-packages\discord\ext\commands\core.py", line 62, in wrapped
ret = yield from coro(*args, **kwargs)
File "C:\Users\user\Desktop\Code\bot.py", line 44, in kick
await client.kick(user)
AttributeError: 'Client' object has no attribute 'kick'
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "C:\Users\user\AppData\Roaming\Python\Python36\site-packages\discord\ext\commands\bot.py", line 886, in invoke
yield from ctx.command.invoke(ctx)
File "C:\Users\user\AppData\Roaming\Python\Python36\site-packages\discord\ext\commands\core.py", line 493, in invoke
yield from injected(*ctx.args, **ctx.kwargs)
File "C:\Users\user\AppData\Roaming\Python\Python36\site-packages\discord\ext\commands\core.py", line 71, in wrapped
raise CommandInvokeError(e) from e
discord.ext.commands.errors.CommandInvokeError: Command raised an exception: AttributeError: 'Client' object has no attribute 'kick'
I tried searching various different youtube videos and posts related to the problem I am having but nobody seems to be having a solution. I have written the code below. If you spot any errors which I missed please let me know.
import time
import random
import discord
import asyncio
from discord.ext import commands
#Initialize
client = discord.Client()#Creates Client
bot = commands.Bot(command_prefix='!')#Sets prefix for commands(!Command)
#bot.event
async def on_ready():
print('Name:', end=' ')
print(bot.user.name)
print('ID: ')
print(bot.user.id)
#bot.command(pass_context=True)
async def user_info(ctx, user: discord.Member):
await ctx.send(f'The username of the user is {user.name}')
await ctx.send(f'The ID of the user is {user.id}')
await ctx.send(f'The status of the user is {user.status}')
await ctx.send(f'The role of the user is {user.top_role}')
await ctx.send(f'The user joined at {user.joined_at}')
#bot.command(pass_context=True)
async def kick(ctx, user: discord.Member):
await ctx.send(f'The Kicking Hammer Has Awoken! {user.name} Has Been Banished')
await client.kick(user)
bot.run('SECRET')
client.run('SECRET')
You appear to be using the newer discord.py 1.0, also called the rewrite branch. You should read this, which is the documentation of the many breaking changes that were made in that switch. You should also refer solely to that documentation, as most documentation for the older 0.16 version is not compatible.
Many things were moved out of Client and into places that made a little more sense. Specifically, kick is now a method of Guilds.
import asyncio
from discord.ext import commands
bot = commands.Bot(command_prefix='!')
#bot.event
async def on_ready():
print('Name:', end=' ')
print(bot.user.name)
print('ID: ')
print(bot.user.id)
#bot.command(pass_context=True)
async def user_info(ctx, user: discord.Member):
await ctx.send(f'The username of the user is {user.name}')
await ctx.send(f'The ID of the user is {user.id}')
await ctx.send(f'The status of the user is {user.status}')
await ctx.send(f'The role of the user is {user.top_role}')
await ctx.send(f'The user joined at {user.joined_at}')
#bot.command(pass_context=True)
async def kick(ctx, user: discord.Member):
await ctx.send(f'The Kicking Hammer Has Awoken! {user.name} Has Been Banished')
await ctx.guild.kick(user)
bot.run('secret')
Note that I've also removed all references to client in the above. Bot is a subclass of Client, so you can access all the Client methods through Bot.

Categories