DM commands to discord bot - python

I recently had the idea of DMing my bot commands. For example, a command which would unban me from every server that the bot is on.
Unfortunately I don't have any starting point for the command because I'm not even sure DMing commands is possible.
Keywords like discord.py, command or DM are so common in google that finding any good info on the topic is very hard.
I'm looking for a way for the bot to receive DMs as commands and only accept them from me (my ID is stored in the variable ownerID if anyone wants to share any code).
While I'm mostly looking for the above, some code for the DM unban command would also be very helpful.
EDIT: I was asked to show some example code from my bot. Here is the code for the command number which generates a random number and sends it in a message. I hope this gives you an idea of how my bot is made:
#BSL.command(pass_context = True)
async def number(ctx, minInt, maxInt):
if ctx.message.author.server_permissions.send_messages or ctx.message.author.id == ownerID:
maxInt = int(maxInt)
minInt = int(minInt)
randomInt = random.randint(minInt, maxInt)
randomInt = str(randomInt)
await BSL.send_message(ctx.message.channel, 'Your random number is: ' + randomInt)
else:
await BSL.send_message(ctx.message.channel, 'Sorry, you do not have the permissions to do that #{}!'.format(ctx.message.author))

You can send commands in private messages. Something like
#BSL.command(pass_context=True)
async def unban(ctx):
if ctx.message.channel.is_private and ctx.message.author.id == ownerID:
owner = await BSL.get_user_info(ownerID)
await BSL.say('Ok {}, unbanning you.'.format(owner.name))
for server in BSL.servers:
try:
await BSL.unban(server, owner) # I think having the same name should be fine. If you see weird errors this may be why.
await BSL.say('Unbanned from {}'.format(server.name))
except discord.HTTPException as e:
await BSL.say('Unbanning failed in {} because\n{}'.format(server.name, e.text))
except discord.Forbidden:
await BSL.say('Forbidden to unban in {}'.format(server.name))
else:
if ctx.message.author.id != ownerID:
await BSL.say('You are not my owner')
if not ctx.message.channel.is_private:
await BSL.say('This is a public channel')
should work. I'm not sure what happens if you try to unban a user who is not banned, that may be what raises HTTPException

Related

discord bot can't handle requests from different users

im trying to create a chatbot that has conversations sequentially like this. this works with one user fine but if another user tries to use the bot at the same time it interferes with the first user. I understand I would have to use some sort of asynchronous programming to fix this but I'm not sure how. any help would be appreciated
#client.event
async def on_message(msg):
if msg.author.bot:
return
if msg.content == "hey":
await msg.channel.send('hi')
response = await client.wait_for('message')
if response.content =="how are you":
await response.channel.send('good')
client.run(token)
Explanation
response = await client.wait_for('message') will catch any message sent after the command is executed, regardless of whom it's from.
This can be rectified by adding a check to wait_for, like in the code below.
Code
response = await client.wait_for('message', check=lambda message: message.author == msg.author)
Reference
wait_for
lambda expressions

Bot isn't responding to my function calls

I need my Discord bot to handle DM's and therefore I wrote this script:
#client.command()
async def dm(ctx, user_id=None, *, args=None):
if user_id != None and args != None:
try:
target = await client.fetch_user(user_id)
await target.send(args)
await ctx.channel.send("'" + args + "' sent to: " + target.name)
except:
await ctx.channel.send("Couldn't dm the given user.")
else:
await ctx.channel.send("You didn't provide a user's id and/or a message.")
My problem now is, until this point in my project I was satisfied by coding if-else-branches into the "on_message()"-function in order to make my bot react to certain commands but now my bot isn't reacting to function calls: When I try to call the "dm"-function (my command prefix is set to ".") it doesn't throw an error in the console it just doesn't work and I'm clueless to what I'm doing wrong here.
Is the code snippet not located in the right place inside my script? What am I missing?
I'd be glad for any form of help. Thanks
As per the docs, you need to add a await client.process_commands(message) at the end of your on_message listener.
https://discordpy.readthedocs.io/en/master/faq.html#why-does-on-message-make-my-commands-stop-working
Edit: Separate question but as I wrote in the comment, here's an example on DM'ing people on a certain time:
from discord.ext import tasks
#tasks.loop(hours=24*7)
async def dm_loop():
user_ids = (123, 456, 789)
for i in user_ids:
user = await client.fetch_user(i)
await user.send("hello")
#client.event
async def on_ready():
dm_loop.start() #remember to add this to your on_ready event
This would make it run on startup and then once a week.

discord.py :: massban command not properly banning and sending embed messages upon completion

Whenever I run my code in VSC, I'm not getting any errors in my terminal so I have no idea where to go from here.
When I run the command, it should be !massban . Upon doing this, it should check to make sure the users are in the server or not as well as checking to make sure a reason is given. After, it should send the users an embed message telling them that they were banned and the reason for it while sending another embed to a log channel to show who actioned the user and the reason for it. Finally, the users will be banned while showing how many successful bans there were / how many failed.
Unfortunately, upon using this command, it does not check to see if the member is in the server or not as well as not checking if a reason is included. It will only ban the first ID given, not send an embed message to the user, and only sends one log to the mod log channel without saying how many successful bans there were / how many failed. (I was using alt accounts to test this on and they both have the ability to receive messages from my server.)
This is my code:
#client.command()
#commands.has_any_role("Head Honcho", "Discord Moderator")
async def massban(ctx, member : commands.Greedy[discord.Member], *, reason: Optional[str]):
if member is None:
return await ctx.send("This member could not be found, or you did not provide an ID.")
if reason is None:
return await ctx.send("Please provide a reason for banning this user.")
success = 0
failures = 0
for user in member:
try:
embed = discord.Embed(title = "You have been **banned** from 🎊 Cold's Jamboree 🎉" , description = "A moderator has banned you regarding your behavior." , color = discord.Color.from_rgb(204,0,0))
embed.add_field(name = "Reason:", value = "{reason}".format(reason=reason) , inline = True )
embed.set_thumbnail(url=ctx.guild.icon_url)
try:
await member.send(embed=embed)
await ctx.guild.ban(user, delete_message_days=1)
except discord.HTTPException:
pass
success +=1
except discord.HTTPException:
failures +=1
finally:
channel = client.get_channel(820100484358471701)
embed = discord.Embed(title = f"", description = "**[🔨] A 'mass ban' has been issued.**", color = discord.Color.from_rgb(204,0,0), timestamp = ctx.message.created_at)
embed.add_field(name = f" `{ctx.author.name}` has banned `{user.name}`.\n\nReason:", value = "{reason}".format(reason=reason))
embed.set_author(name = f"{user} ({user.id})", icon_url = user.avatar_url)
embed.set_footer(icon_url = ctx.author.avatar_url, text = "Modlog created ")
try:
await channel.send(embed=embed)
except discord.HTTPException:
pass
if ctx.channel.id == 805651955841236993:
reaction_emote = ("<:Checkmark:820467149554319410>")
await ctx.message.add_reaction(reaction_emote)
await ctx.send("Massbanned " + str(success) + " members.\n{}".format(f"Failed {failures} members." if failures else ""))
I would be extremely grateful if someone could help me out. With VSC not giving me any errors, I'm confused as to what's going on because it should work.
you should not do this, discord hates when people do it because it's hard to tell from nuking (where people make bots to ban everyone) or if it's real so most of the time they will block it if it's not delayed like 10s or really slow.

How can I show who my bot is DMing and cannot DM. (discord.py)

I understand the question is not phrased correctly or may not make any sense, so I will give a little context and information as to what I am trying to do...
Context
I am trying to create a bot that DMs everyone in my server to remind them of such and such, I have mastered the code on how to do this but I am having troubles figuring out how to make it show, who the bot is DMing and who it is not DMing.
I have researched for quite a bit and haven't found a solution which lead me here.
Question
How can I show who my bot is DMing and cannot DM. (The bot does do what it is supposed to do, DM everyone in the server upon request but I want it to be shown via terminal/pycharm/IDE.
Ex: User#1000 has successfully messaged User#2000!
import discord
import os, time, random
from discord.ext import commands
from lol import token
client = discord.Client()
intents = discord.Intents.all()
client = commands.Bot(command_prefix="!", intents=intents, self_bot = True)
#client.event
async def on_ready():
print("Ready!")
#client.command()
async def dm_all(ctx, *, args=None):
if args != None:
members = ctx.guild.members
for member in members:
try:
await member.send(args)
await print(ctx.discriminator.author)
except:
print("Unable to DM user because the user has DMs off or this is a bot account!")
else:
await ctx.send("Please provide a valid message.")
client.run(token, bot=True)
Here are some important things to know:
If a user cannot receive a DM, then you get an Forbidden error.
You can use except statements to log these errors and display them in the console.
Most of the time you can't send direct messages to bots, then you get an HTTPException error.
Have a look at the following code:
#client.command()
async def dm_all(ctx, *, args=None):
if args is not None:
members = ctx.guild.members
for member in members:
try:
await member.send(args)
print(f"Sent a DM to {member.name}")
except discord.errors.Forbidden:
print(f"Could not send a DM to: {member.name}")
except discord.errors.HTTPException:
print(f"Could not send a DM to: {member.name}")
else:
await ctx.send("Please provide a valid message.")
Output:
Sent a DM to Dominik
Could not send a DM to: BotNameHere
Of course you can customize member.name according to your wishes.
Reference:
https://discordpy.readthedocs.io/en/latest/api.html?highlight=forbidden#discord.Forbidden

discord.py command cooldown for ban command

I've got this code for my bot, which allows banning users for certain people. However, is there a way to make it so that a staff member can only use the ban command once every 2 hours. I want every other command to have no cooldown, but just for the ban command, have a way to only allow it to be used once per 2 hours per user. Here's the code I've got so far:
#commands.has_permissions(administrator=True)
async def pogoban (ctx, member:discord.User=None, *, reason =None):
if member == None or member == ctx.message.author:
await ctx.channel.send("You cannot ban yourself")
return
if reason == None:
reason = "For breaking the rules."
message = f"You have been banned from {ctx.guild.name} for {reason}"
await member.send(message)
await ctx.guild.ban(member, reason=reason)
await ctx.channel.send(f"{member} is banned!")
What would I need to add/change to add a command cooldown of 2 hours per user for this command. I've tried looking around, but I've only found ways to make all commands have a cooldown, instead of this one specific command. Thanks!
How about something like this:
cooldown = []
#client.command()
async def pogoban(ctx, member: discord.Member = None, *, reason = None):
author = str(ctx.author)
if author in cooldown:
await ctx.send('Calm down! You\'ve already banned someone less that two hours ago.')
return
try:
if reason == None:
reason = 'breaking the rules.'
await member.send(f'You have been banned from **{ctx.guild.name}** for **{reason}**')
await member.ban(reason = reason)
await ctx.send(f'{member.mention} has been banned.')
cooldown.append(author)
await asyncio.sleep(2 * 60 * 60) #The argument is in seconds. 2hr = 7200s
cooldown.remove(author)
except:
await ctx.send('Sorry, you aren\'t allowed to do that.')
Note: Remember to import asyncio. Also remember that once your bot goes offline, all the users stored in the list will be erased.
Please Read
A better approach would be to store the time of banning along with the the authors name and check if the current time is at least an hour more than the saved time. And to make it a lot safer, the authors name along with the time can be saved in a database or an external text file, this way your data won't get erased if the bot goes offline.

Categories