Hello so i am trying to create a report system where when a report is created it is report #0001 when a new one is it is report #0002 here is my code so far.
#commands.command()
async def report(self, ctx, member : discord.Member, reason=None):
await ctx.send(f'{member} has been reported!')
channel = discord.utils.get(ctx.guild.text_channels, name='reports')
embed = discord.Embed(name=f'Report incoming! #0001 ')
embed.add_field(name='Member', value=f'{member}', inline=False)
embed.add_field(name='Member who reported them', value=f'{ctx.author}', inline=False)
embed.add_field(name='Reason', value=f'{reason}', inline=False)
embed.add_field(name='Channel', value=f'{ctx.channel}', inline=False)
await channel.send(content=None, embed=embed)
Does anyone know how if so please respond to this thanks!
If you sure that there will be no internet problem or some other problems that will prevent the boat from running, you can simply do
count = 0
#commands.command()
async def report(self, ctx, member : discord.Member, reason=None):
count += 1
#the rest of the command
Then you can change the embed name like this
embed = discord.Embed(name=f'Report incoming! #{count}')
But if you are not completely sure that the bot will have not any problem,
you can save the numbers in a file like txt, json or yaml. I'd prefer txt in that case because you just need to save one line of text. So you can do this:
with open('counts.txt', 'r+') as file:
number = file.read()
if number == '':
file.write('0')
#commands.command()
async def report(self, ctx, member : discord.Member, reason=None):
with open('counts.txt', 'w+') as file:
count = file.read()
file.write(int(count)+1)
embed = discord.Embed(name=f'Report incoming! #{count}')
Well, you have to store the report count somewhere, preferably a proper database. For this example you can use a json file, however, keep in mind that a json file as a database is fundamentally flawed due to its lack of atomic writes which can result in data corruption and loss.
import json
#commands.command()
async def report(self, ctx, member: discord.Member, reason=None):
# Get currect report number
with open('reports.json', 'r', encoding='utf-8') as counts:
data = json.load(counts)
counter = data['count']
await ctx.send(f'{member} has been reported!')
data = {"count": counter + 1} # Add 1 everytime a report is invoked
with open('reports.json', 'w', encoding='utf-8') as f:
json.dump(data, f, ensure_ascii=False, indent=4)
channel = discord.utils.get(ctx.guild.text_channels, name='reports')
embed = discord.Embed(title=f'Report incoming! #{counter} ')
embed.add_field(name='Member', value=f'{member}', inline=False)
embed.add_field(name='Member who reported them', value=f'{ctx.author}', inline=False)
embed.add_field(name='Reason', value=f'{reason}', inline=False)
embed.add_field(name='Channel', value=f'{ctx.channel}', inline=False)
await channel.send(content=None, embed=embed)
reports.json
{
"count": 0
}
Related
Can anyone help? The fact is that I am a novice developer and I can't understand why I get this error in the console. discord.ext .commands.errors.CommandInvokeError: Command raised an exception: TypeError: Embed.add_field() missing 1 required keyword-only argument: 'value'. I seem to be doing everything right.
Here is the code I use:
#bot.command(pass_context=True)
async def ban(ctx, member: discord.Member, *, reason = None):
await ctx.channel.purge(limit=1)
emb = discord.Embed(title = 'Ban')
emb.add_field(name = 'Ban', value = 'Baned user {}'.format(member.mention))
emb.set_author(name = ctx.author.display_name, icon_url = ctx.author.avatar)
await ctx.send(embed = emb)
await member.ban(reason=reason)
For Adding Fields To Embeds, Do Like This :
emb.add_field(name="Field1", value="say Hi", inline=False)
And Use F Strings Like : value = f"Banned User : {member.mention}"
For Better Performance !
More Info
So I'm making a user info command and when i run the command, it doesn't work and gives no error.
Heres my code:
#commands.command()
async def info(self, ctx, *, member: discord.Member):
embed=discord.Embed(color=0xFFFFF0, title=f"{ctx.author.name}'s Info", description="Displays user information.")
embed.set_thumbnail(url=f"{ctx.author.avatar_url}")
embed.add_field(name="User ID:", value=f"{ctx.author.id}", inline=True)
embed.add_field(name="Color:", value=f"{ctx.author.top_role.mention}\n[{ctx.author.top_role.colour}]")
embed.add_field(name="Join Date:", value=f"{ctx.author.joined_at}")
embed.timestamp = datetime.datetime.utcnow()
embed.set_footer(text=f"Requested by: {ctx.author}", icon_url=ctx.author.avatar_url)
await ctx.send(embed=embed)
You basically put ctx.author, which the author is you, you cant show other user's info if you did that. You should use an if statement if you want to show other user's info.
And the last thing is the Joindate. it will send this weird time 04:22:23.699000. So you should convert the time to an strftime.
The Updated Code :
#commands.command()
async def info(self, ctx, *, member: discord.Member = None): #changed the member to None so it will work if the user didnt mention the member
if member == None: # shows that if the use didnt mention the member (if statement)
member = ctx.author
# changed all embed of the ctx.author to member
embed=discord.Embed(title=f"{member.name}'s Info", description="Displays user information.", color=0xFFFFF0)
embed.set_thumbnail(url=f"{member.avatar_url}")
embed.add_field(name="User ID:", value=f"{member.id}", inline=True)
embed.add_field(name="Color:", value=f"{member.top_role.mention}\n[{member.top_role.colour}]")
embed.add_field(name="Join Date:", value= member.joined_at.strftime("%B %d %Y\n%H:%M:%S %p")) # make the time look nice
embed.timestamp = datetime.datetime.utcnow()
embed.set_footer(text=f"Requested by: {ctx.author}", icon_url=ctx.author.avatar_url) # changed member to ctx.author als
await ctx.send(embed=embed)
I have this code for my discord.py bot, for my tempmute command:
#bot.command()
async def tempmute(ctx, member: discord.Member, time: int, d, *, reason=None):
guild = ctx.guild
mutedRole = discord.utils.get(guild.roles, name="Muted")
if not mutedRole:
mutedRole = await guild.create_role(name="Muted")
for channel in guild.channels:
await channel.set_permissions(mutedRole, speak=False, send_messages=False)
for role in guild.roles:
if role.name == "Muted":
await member.add_roles(role)
embed = discord.Embed(title="TempMuted!", description=f"{member.mention} has been tempmuted.", colour=discord.Colour.red())
embed.add_field(name="Reason:", value=reason, inline=False)
embed.add_field(name="Time for the mute:", value=f"{time}{d}", inline=False)
await ctx.send(embed=embed)
if d == "s":
await asyncio.sleep(time)
if d == "m":
await asyncio.sleep(time*60)
if d == "h":
await asyncio.sleep(time*60*60)
if d == "d":
await asyncio.sleep(time*60*60*24)
await member.remove_roles(role)
embed = discord.Embed(title="Unmute (temp mute expired) ", description=f"Unmuted -{member.mention} ", colour=discord.Colour.light_gray())
await ctx.send(embed=embed)
return
However, when using the command, it has to be typed like this: "!tempmute #user 10 m" if I wanted a 10 minute mute. Notice how it is "10 m". How would I make it so "10m" would work (without a space). So "!tempmute #user 10m"? If a user writes it without a space at the moment, the error "discord.ext.commands.errors.BadArgument: Converting to "int" failed for parameter "time"." occurs, probably as it isn't recognising a number with the letter at the end. Thanks
The best way to solve this would be to create your own Converter and typehint the class in the argument. As documented here
So instead of converting your time in your command function, you would do it in the converter making the syntax more cleaner.
Example of a converter
time_regex = re.compile(r"(\d{1,5}(?:[.,]?\d{1,5})?)([smhd])")
time_dict = {"h":3600, "s":1, "m":60, "d":86400}
class TimeConverter(commands.Converter):
async def convert(self, ctx, argument):
matches = time_regex.findall(argument.lower())
time = 0
for v, k in matches:
try:
time += time_dict[k]*float(v)
except KeyError:
raise commands.BadArgument(f"{k} is an invalid time-key! h/m/s/d are valid!")
except ValueError:
raise commands.BadArgument(f"{v} is not a number!")
return time
This is an example of a Time converter, where it will use a regex and converts it into an int in seconds. Which accepts <number><smhd>, example 2d.
The library calls TimeConverter().convert during the command invocation, hence we create a method called convert, which accepts Context object and arguments as str. All you have to do is return something, or raise an error if there is an error.
In order to use this, you would do it as follows
#bot.command()
async def tempmute(ctx, member: discord.Member, time: TimeConverter, *, reason=None):
...
await member.add_roles(role)
await asyncio.sleep(time)
await member.remove_roles(role)
...
The command invocation would be
!tempmute #user 2d here's the reason
I have been working on a tempmute command myself. I would say the command would work fine with a simple dictionary. If you want to convert time units a simple dictionary would do it and you wouldn't require a hell lot of code.
First I would add the code and then give a brief explanation.
Code:
#MyBot.command()
#commands.has_permissions(manage_roles=True)
async def tempmute(ctx, member: discord.Member, time, *, reason=None):
await ctx.message.delete()
if member.guild_permissions.administrator:
ifadmin_embed = discord.Embed(title='Member is Administrator!', description=f'The user, {member.mention} can\'t be muted as he/she is an administrator.', color=0xff0000)
ifadmin_embed.set_author(name='NucleoBot')
ifadmin_embed.set_footer(text=ctx.author)
await ctx.channel.send(embed=ifadmin_embed, delete_after=10.0)
else:
if discord.utils.get(ctx.guild.roles, name='Muted'):
muted_role = discord.utils.get(ctx.guild.roles, name='Muted')
else:
perms = discord.Permissions(send_messages=False, add_reactions=False, connect=False, speak=False)
await ctx.guild.create_role(name='Muted', permissions=perms)
muted_role = discord.utils.get(ctx.guild.roles, name='Muted')
time_convert = {'s' : 1 , 'm' : 60 , 'h' : 3600 , 'd' : 86400, 'y' : 31536000}
mute_time = int(time[0]) * time_convert[time[-1]]
await ctx.message.delete()
role_if_muted = discord.utils.find(lambda r: r.name == 'Muted', ctx.guild.roles)
if role_if_muted in member.roles:
alreadymuted_embed = discord.Embed(title='Already Muted!', description=f'The user, {member.mention} is already muted for {mute_time} seconds.', color=0xff0000)
alreadymuted_embed.set_footer(text=ctx.author)
alreadymuted_embed.set_author(name='NucleoBot')
await ctx.channel.send(embed=alreadymuted_embed, delete_after=10.0)
else:
if reason == None:
await member.add_roles(muted_role)
tempmuted_embed = discord.Embed(title='Temporary Mute Successfull!', description=f'{member.mention} has been muted for {mute_time} seconds successfully! \n \n Reason: No reason given.', color=0x4fff4d)
tempmuted_embed.set_author(name='NucleoBot')
tempmuted_embed.set_footer(text=ctx.author)
else:
await member.add_roles(muted_role)
tempmuted_embed = discord.Embed(title='Temporary Mute Successfull!', description=f'{member.mention} has been muted for {mute_time} seconds successfully! \n \n Reason: {reason}', color=0x4fff4d)
tempmuted_embed.set_author(name='NucleoBot')
tempmuted_embed.set_footer(text=ctx.author)
await ctx.channel.send(embed=tempmuted_embed, delete_after=10.0)
await asyncio.sleep(mute_time)
await member.remove_roles(muted_role)
Explanation:
My code has almost everything here that you need for a mute command. Only the members with roles that have manage_role permissions to execute this command. Also if someone try to mute a member who is an administrator of the server, an embed would pop up to say, Member is an admin.
The code also has the aspect that if no reason is given it would not show any error but post an embed made for No Reason command, i.e., if no reason is mentioned. It also checks that if the server doesn't have a role named Muted. It the role exist it would simply use it otherwise first it would create a role named Muted with denial of important permissions and use it for the mute.
Now the time conversion. The line which is used for this:
time_convert = {'s' : 1 , 'm' : 60 , 'h' : 3600 , 'd' : 86400, 'y' : 31536000}
This command takes second as basic value for the conversion then converts every other unit in terms of seconds. Here s is equated to 1 and m is equated to 60 as I minute is equal to 60 seconds. Similarly doing that same with other units we derive everything to seconds. This dictionary turns everything to seconds and using asyncio we create a timer for mute.
Hope this helps, if you still get any doubt, please feel free to ask me.
Thank You!
Here is what I got so far
It is saying that "await" is outside of async function and I am just confused on how to fix this. I copied part of the code from a giveaway command because that is my only source of Q&A code I have
#commands.has_permissions(administrator = True)
async def cdelete(ctx):
embed=discord.Embed(title = Which channel would you like to delete?)
await ctx.send(embed=embed)
answer = []
def check(m):
return m.author == cx.author and m.channel == ctx.channel
try:
await client.wait_for('message', timeout=15, check=check)
except asyncio.TimeoutError:
await ctx.send("Timeout. Please run the command again")
else:
answer.append(message.content)
try:
c_id= int(answer[0][2:-1])
await ctx.channel.delete
await ctx.send("Channel Deleted")
except:
await ctx.send("Thats not a valid channel!")```
If you just want a command you can make it a lot easier if you just execute a command with the channel name. You can have a look at the following:
#client.command()
#commands.has_permissions(administrator=True)
async def cdelete(ctx, channel_name):
"""Deletes a channel by name or ID."""
channel_id = int(''.join(i for i in channel_name if i.isdigit())) # Get channel ID
existing_channel = client.get_channel(channel_id) # Get channel ID with defined method
if existing_channel: # If channel with the name/ID exists
await existing_channel.delete()
else: # If the channel does not exist
await ctx.send(f'**No channel named `{channel_name}` was found.**')
We have a method to catch the channel ID and also pass that in as a valid argument. If the ID or channel name then exists we delete the channel.
You can here either mention the channel or pass in the ID.
Usage would be: cdelete #channel/ID.
If you want to avoid a long console output if you input no channel/ID/name you can build in an error handler:
#cdelete.error
async def cdelete_error(ctx, error):
if isinstance(error, commands.MissingRequiredArgument):
await ctx.send("You need to name a channel.")
The problem you have here is with the check() function. According to the doc you only can use await inside of an async function. To solve the problem change def check(m): into async def check(m):
Ok so I'm working on one of my older bots and am attempting to rewrite my custom help command to be a bit less manual. However, I'm not sure how to get this working as intended.
My issues are as follows:
It keeps responding with the I can't send embeds exception
There's no error showing up in the console logs
Can anyone help me figure this out?
Here is my custom Help command.
#commands.command(name="help", aliases=["Help", "H", "h"])
#commands.has_permissions(add_reactions=True, embed_links=True)
async def help(self, ctx, *cog):
"""Gets all cogs and commands.
Alt : h, H, Help
Usage : [h]elp <cog or command>"""
try:
if not cog:
"""Cog listing. What more?"""
embed = discord.Embed(color=discord.Color.dark_gold(),
title='Cog Listing and Uncatergorized Commands',
description=f'Use `{prefix}help <cog>` to find out more about them!\nNote: The Cog Name Must Be in Title Case, Just Like this Sentence.',
timestamp=ctx.message.created_at)
embed.set_author(name=self.client.user.name, icon_url=self.client.user.avatar_url)
cogs_desc = ''
for x in self.client.cogs:
cogs_desc += ('{} - {}'.format(x, self.client.cogs[x].__doc__) + '\n')
embed.add_field(name='Cogs', value=cogs_desc[0:len(cogs_desc) - 1], inline=False)
cmds_desc = ''
for y in self.client.walk_commands():
if not y.cog_name and not y.hidden:
cmds_desc += ('{} - {}'.format(y.name, y.help) + '\n')
embed.add_field(name='Uncatergorized Commands', value=cmds_desc[0:len(cmds_desc) - 1], inline=False)
await ctx.send('', embed=embed)
else:
"""Helps me remind you if you pass too many args."""
if len(cog) > 1:
embed = discord.Embed(color=discord.Color.dark_red(), timestamp=ctx.message.created_at)
embed.set_author(name="Command Failed", icon_url=self.client.user.avatar_url)
embed.add_field(name="Error", value="Too many cogs", inline=False)
await ctx.send('', embed=embed)
else:
"""Command listing within a cog."""
found = False
for x in self.client.cogs:
for y in cog:
if x == y:
embed = discord.Embed(color=discord.Color.dark_gold(), timestamp=ctx.message.created_at, title=cog[0] + ' Command Listing', description=self.client.cogs[cog[0]].__doc__)
for c in self.client.get_cog(y).get_commands():
if not c.hidden:
embed.add_field(name=c.name, value=c.help, inline=False)
found = True
if not found:
"""Reminds you if that cog doesn't exist."""
embed = discord.Embed(color=discord.Color.dark_red(), timestamp=ctx.message.created_at)
embed.set_author(name="Command Failed", icon_url=self.client.user.avatar_url)
embed.add_field(name="Error", value='Can not use "' + cog[0] + '"?', inline=False)
else:
await ctx.send('', embed=embed)
except:
await ctx.send("I can't send embeds.")
I'm using discord.py-rewrite if it helps.
---EDIT---
I gave up on the above code due to countless issues with it. And went for the following code. I'd still like it to be less manual but for now this one actually posts.
#commands.command(name="Help", aliases=["help", "h", "H"])
async def _help(self, ctx):
"""Displays all available commands"""
msg = ctx.message
await msg.delete()
contents = [
f"```css\nAdministrator Commands\n\nBroadcast: [B]roadcast <message>\nPurge: [p]urge <1-100>\nBan: [B]an <user> [reason]\nUnban: [U]nban <user>\nKick: [K]ick <user> [reason]\n\nOptional arguments are represented with []\nRequired arguments are represented with <>\nDo not include the [] or <> flags in the command\n ```",
f"```css\nModerator Commands!\n\nAnnounce: [ann]ounce <message>\nClean: [C]lean <1-100>\n\nOptional arguments are represented with []\nRequired arguments are represented with <>\nDo not include the [] or <> flags in the command\n ```",
f"```css\nFun Commands\n\nGiphy: [ ] < >\nTenor: [ ] < >\n\nOptional arguments are represented with []\nRequired arguments are represented with <>\nDo not include the [] or <> flags in the command\n ```",
f"```css\nUtility Commands\n\nPing: ping\nJoined: [J]oined [user]\nTopRole: [top]role [user]\nPerms: perms [user]\nHelp: [H]elp [command]\n\nOptional arguments are represented with []\nRequired arguments are represented with <>\nDo not include the [] or <> flags in the command\n ```"
]
pages = 4
cur_page = 1
message = await ctx.send(f"Page {cur_page}/{pages}:\n{contents[cur_page-1]}")
# getting the message object for editing and reacting
await message.add_reaction("◀️")
await message.add_reaction("▶️")
def check(reaction, user):
return user == ctx.author and str(reaction.emoji) in ["◀️", "▶️"]
# This makes sure nobody except the command sender can interact with the "menu"
while True:
try:
reaction, user = await self.client.wait_for("reaction_add", timeout=60, check=check)
# waiting for a reaction to be added - times out after x seconds, 60 in this
# example
if str(reaction.emoji) == "▶️" and cur_page != pages:
cur_page += 1
await message.edit(content=f"Page {cur_page}/{pages}:\n{contents[cur_page-1]}")
await message.remove_reaction(reaction, user)
elif str(reaction.emoji) == "◀️" and cur_page > 1:
cur_page -= 1
await message.edit(content=f"Page {cur_page}/{pages}:\n{contents[cur_page-1]}")
await message.remove_reaction(reaction, user)
else:
await message.remove_reaction(reaction, user)
# removes reactions if the user tries to go forward on the last page or
# backwards on the first page
except asyncio.TimeoutError:
await message.delete()
break
# ending the loop if user doesn't react after x seconds
#_help.error
async def _help_error(self, ctx, error):
if isinstance(error, commands.MissingRequiredArgument):
guild = ctx.guild
embed = discord.Embed(
color=discord.Color.dark_red(), timestamp=ctx.message.created_at)
embed.set_author(name="Command Failed",
icon_url=self.client.user.avatar_url)
embed.add_field(name="Missing Required arguments",
value="Please pass in all required arguments.", inline=False)
embed.set_thumbnail(url=self.client.user.avatar_url)
embed.set_footer(text=f"{guild.name}", icon_url=guild.icon_url)
await ctx.message.add_reaction(emoji="⚠️️")
await ctx.message.author.send(embed=embed)
print("[ERROR] Missing Required Arguments")
elif isinstance(error, commands.MissingPermissions):
guild = ctx.guild
embed = discord.Embed(
color=discord.Color.dark_red(), timestamp=ctx.message.created_at)
embed.set_author(name="Access denied",
icon_url=self.client.user.avatar_url)
embed.add_field(name="Insufficient Permissions",
value="You do not have permission to use this command.", inline=False)
embed.set_thumbnail(url=self.client.user.avatar_url)
embed.set_footer(text=f"{guild.name}", icon_url=guild.icon_url)
await ctx.message.add_reaction(emoji="🚫")
await ctx.message.author.send(embed=embed)
print("[ERROR] Insufficient Permissions")
But yes, if anyone knows how to make it so the commands are read from the cogs instead of manually typed into the help command's response any tips would be very helpful.