Discord.py - send private message - python

I am using Replit to make a discord bot.
if msgtxt in listBadWords:
await message.channel.send(mention + ", your message has been reported to Arunga")
await message.channel.send("Please do not repeat the same mistake again. Do not say bad words!")
user = client.get_user(int(userid))
await user.send("Arunga, someone said a bad word!")
listBadWords contains a list of bad words. I want to send a dm to the owner, Arunga, saying 'Someone said a bad word!' But when I run the code, and test it out, an error comes
AttributeError:'NoneType' object has no attribute 'send' for
await user.send("Arunga, someone said a bad word!")
I did put the user is in userid, I just didn't want to post the id here.
How do I fix this? Also, this is under async def on_message():

This is because User has no method send, Member has that, so What I did was get the owner of the server (which stored in member) and then send the message.

Related

How to make a ckeck of user permissions in disnake or discord.py

I've got a code with permissions. I need to check a member permissions and if member don`t have such permissions send a message
Main code:
#commands.slash_command(name = "addrole", description="Додати користувачу роль")
#commands.has_permissions(view_audit_log=True)
async def addrole(self, ctx, member: disnake.Member, role: disnake.Role):
#try:
await member.add_roles(role)
emb = disnake.Embed(title=f"Видача ролі", description=f"Користувачу {member.mention} було видано роль {role.mention} на сервері {ctx.guild.name}\n Видав модератор - **{ctx.author.mention}**", colour=disnake.Color.blue(), timestamp=ctx.created_at)
await ctx.send(embed=emb)
What i want to have:
#commands.slash_command(name = "addrole", description="Додати користувачу роль")
#commands.has_permissions(view_audit_log=True)
async def addrole(self, ctx, member: disnake.Member, role: disnake.Role):
if ctx.author.guild_permissions.view_audit_log:
await member.add_roles(role)
emb = disnake.Embed(title=f"Видача ролі", description=f"Користувачу {member.mention} було видано роль {role.mention} на сервері {ctx.guild.name}\n Видав модератор - **{ctx.author.mention}**", colour=disnake.Color.blue(), timestamp=ctx.created_at)
await ctx.send(embed=emb)
else:
await ctx.send("You don`t have such permissions!")
Please, help me. I tried diferrent variants and no one working
I think you are not getting what you want because you are trying to integrate both at once. From what I can see from your description and code, the easiest solution I could provide you is removing #commands.has_permissions(view_audit_log=True) from your "what I want to have" section of code. However, if you don't want to have to add an extra if and else statement sending "you dont have permissions" to the user under every command, I would suggest creating an error handler. Using this method, you would be able to use the first block of code you have listed in your question. Here is a very basic sample of the one I use which deals with a user not having permissions to use a certain command. You'll probably need to change it to fit your specific bot but it's a start:
#client.event
async def on_command_error(ctx, error)
await ctx.send(error) # this sends the error where the user is attempting to use a command. This means if the user is missing the right permissions to use a command, it will send something like "missing permissions" to the user. Which I think is what you are looking for
The "what I want to have" code is not working because the code you have under it is unreachable unless the user has the audit_log permissions. And if they already have those permissions, the if and else statements checking permissions are not very useful. An error handler is in my opinion good to have and has helped me a ton with my bots. Hope this helps

Say command that disables #everyone for non-administrators

EDIT: I have fixed the code by just using another method, thanks for the other helpful answers though!
I'm making a say command, it just takes the user's message and repeats it via the bot. But it can be abused to ping everyone etc. So I want to make it so when the User isn't an admin it checks the message for #everyone or #here. Then it says that you can't ping everyone and reacts to the output 'You cant ping everyone' message with a custom command.
It's also in a cog btw. The command, when used, doesn't throw any console errors, instead not doing anything.
EDIT: I have fixed the code by just using another method, thanks for the other helpful answers though!
#commands.command()
async def say(self, ctx, *, message):
await ctx.message.delete()
if not ctx.message.author.guild_permissions.administrator:
if "#everyone" in message or "#here" in message:
antiping = "You can't mention everyone through me!"
await ctx.send(antiping)
await antiping.add_reaction(emoji=':Canteveryone:890319257534103603')
return
else:
await ctx.message.delete()
await ctx.send(message)
You can use allowed_mentions for this. Two ways of using this:
Pass in Bot when initializing:
client = bot(.....,
allowed_mentions = discord.AllowedMentions(everyone = False)
)
You can also pass the same object when sending a message:
ctx.send(...,
allowed_mentions = discord.AllowedMentions(everyone = False)
)
I'd recommend you read the docs for more info on how it works.
You can adjust mentions for the following attributes:
everyone
replied_user
roles
users
A way of doing this would be when you execute your command, it modifies the role "everyone" so that they cant ping the role
Admins bypass ALL restrictions so they would still be able to ping the role besides

Discord.py How to use the message that the bot WILL send?

import discord
from discord.ext import commands
async def anyfunc(ctx):
await ctx.send(f"{ctx.message.author.mention}, "Hi!")
bot_message_id = ((bot's_last_message)).id
What to put in (()) to make the bot remember the id of the message that it will send?
Is there a way to take the id of the next (for example, user's) message (that hasn't been sent yet) as a variable?
ctx.send() returns the discord.Message instance of the message it sent, so you can store it in a variable.
message = await ctx.send(f"{ctx.message.author.mention}, Hi!")
# do what you want with the message, in your case getting it's id
bot_message_id = message.id
As for your second question, if you want to get the response of a user to that message (so the next message a specific user will send), you can use the built-in wait_for for this.
def check(message):
return message.author.id == the_id_of_that_user
message = await bot.wait_for("message", check=check)
That way, the bot will literally wait for a message that makes your check function return True, or in this case a message sent by that very user. More info on that in the relevant API documentation.
I couldn't understand your question very good but I'll try to answer. according to API References you can get someone's last message with using channel.history().get(). So here is a example:
import discord
from discord.ext import commands
async def anyfunc(ctx):
await ctx.send(f"{ctx.message.author.mention}, Hi!")
bot_message_id = await ctx.channel.history().get(author__name="Bot's name").id
This will probably work but in case of error, maybe you can try author__id=bot's id instead of author__name.

Send message to dms discord.py

I want to send message to dms using my discord bot and because the api has changed from client.send_message(user, message) to channel.send(message) I have no idea how to do that, also I dont want to make it dependent on the on_message(message) event. Any ideas?
If you have the user ID you can do:
user = client.get_user(user_id)
await user.send('Hello')
However If you already have the User object, you can do the following:
await message.author.send('Hey')
Where message is a Message object received from a on_message() event.
As for whether you can send private messages without first receiving an event unfortunately that is not be possible due to obvious spam-related issues.

Discord.py How do I delete a singular message in the rewrite

I want to delete a singular message when triggered but I cannot figure it out. I got purge working with await ctx.channel.purge but that's not what I want since that requires an amount
The old version was written like await self.bot.delete_message(ctx.message) but that now brings the error object has no attribute 'bot'
Reading the documentation all I could find was Message.delete but that brings the error: NameError: name 'Message' is not defined
I am sure this is a simple solution but I cannot work it out. Thanks in advance
My current code is:
#commands.command(pass_context=True)
async def say(self, ctx, *args):
'''Make Bot repeat your messages'''
mesg = ' '.join(args)
await Message.delete(ctx.message)
await ctx.send(mesg)`
If you are talking about the message that triggered the command, then you can do:
await ctx.message.delete()
You can use await message.delete() to delete the trigger message
(for example, user sends !say hi, bot says hi, and it deletes the user's message "!say hi")
really late here but ok

Categories

Resources