From bcdc94215d78d864c6ace249d27b30e745237801 Mon Sep 17 00:00:00 2001 From: Krypton Date: Sat, 27 Nov 2021 13:18:52 +0100 Subject: [PATCH] Template v4.0 * Now using [`disnake`](https://docs.disnake.dev) * Added a command that uses buttons *(coinflip)* * Added a command that uses selection dropdown *(rps)* * **Every** command is now in slash command **and** normal command (old way with prefix) * Make sure to **enable the message intents** for normal commands as it's now a privileged intent. * The **slash command** is **above**, the **normal command** is **below** --- README.md | 4 +- UPDATES.md | 13 +- bot.py | 110 +++++++++---- cogs/fun.py | 208 +++++++++++++++++++++++-- cogs/general.py | 329 ++++++++++++++++++++++++++++----------- cogs/moderation.py | 331 ++++++++++++++++++++++++++++------------ cogs/owner.py | 212 +++++++++++++++++++------ cogs/template.py | 25 ++- config.json | 2 + exceptions/__init__.py | 9 ++ helpers/checks.py | 10 +- helpers/json_manager.py | 8 + requirements.txt | 3 +- 13 files changed, 980 insertions(+), 284 deletions(-) diff --git a/README.md b/README.md index faf70957..24267c4e 100644 --- a/README.md +++ b/README.md @@ -83,7 +83,9 @@ Here is an explanation of what everything is: | Variable | What it is | | ------------------------- | ----------------------------------------------------------------------| +| YOUR_BOT_PREFIX_HERE | The prefix you want to use for normal commands | | YOUR_BOT_TOKEN_HERE | The token of your bot | +| YOUR_BOT_PERMISSIONS_HERE | The permissions integer your bot needs when it gets invited | | YOUR_APPLICATION_ID_HERE | The application ID of your bot | | OWNERS | The user ID of all the bot owners | @@ -137,7 +139,7 @@ the [tags on this repository](https://github.com/kkrypt0nn/Python-Discord-Bot-Te ## Built With -* [Python 3.9](https://www.python.org/) +* [Python 3.9.9](https://www.python.org/) ## License diff --git a/UPDATES.md b/UPDATES.md index 8945dda7..a5f963f7 100644 --- a/UPDATES.md +++ b/UPDATES.md @@ -2,6 +2,15 @@ Here is the list of all the updates that I made on this template. +### Version 4.0 + +* Now using [`disnake`](https://docs.disnake.dev) +* Added a command that uses buttons *(coinflip)* +* Added a command that uses selection dropdown *(rps)* +* **Every** command is now in slash command **and** normal command (old way with prefix) + * Make sure to **enable the message intents** for normal commands as it's now a privileged intent. + * The **slash command** is **above**, the **normal command** is **below** + ### Version 3.1.1 * Fixed `TypeError: 'NoneType' object is not iterable` for prefix -> Python 3.10 @@ -65,7 +74,7 @@ Here is the list of all the updates that I made on this template. ### Version 2.4 * Added some fun commands -* Colors are saved in the [config file](config.py) for easier usage +* Colors are saved in the [config file](config.json) for easier usage * Cogs are now being loaded automatically * Fixed some typos @@ -89,7 +98,7 @@ Here is the list of all the updates that I made on this template. * Added cogs * Added f-strings and removed `.format()` -* Created [config file](config.py) for easier setup +* Created [config file](config.json) for easier setup ### Version 1.2 diff --git a/bot.py b/bot.py index 94ba2d33..a3910389 100644 --- a/bot.py +++ b/bot.py @@ -3,7 +3,7 @@ Description: This is a template to create your own discord bot in python. -Version: 3.1.1 +Version: 4.0 """ import json @@ -12,10 +12,10 @@ import random import sys -import discord -from discord.ext import tasks -from discord.ext.commands import Bot -from discord_slash import SlashCommand, SlashContext +import disnake +from disnake import ApplicationCommandInteraction +from disnake.ext import tasks, commands +from disnake.ext.commands import Bot import exceptions @@ -28,44 +28,43 @@ """ Setup bot intents (events restrictions) For more information about intents, please go to the following websites: -https://discordpy.readthedocs.io/en/latest/intents.html -https://discordpy.readthedocs.io/en/latest/intents.html#privileged-intents +https://docs.disnake.dev/en/latest/intents.html +https://docs.disnake.dev/en/latest/intents.html#privileged-intents Default Intents: -intents.messages = True -intents.reactions = True -intents.guilds = True -intents.emojis = True intents.bans = True -intents.guild_typing = False -intents.typing = False intents.dm_messages = False intents.dm_reactions = False intents.dm_typing = False +intents.emojis = True intents.guild_messages = True intents.guild_reactions = True +intents.guild_typing = False +intents.guilds = True intents.integrations = True intents.invites = True +intents.reactions = True +intents.typing = False intents.voice_states = False intents.webhooks = False Privileged Intents (Needs to be enabled on dev page), please use them only if you need them: -intents.presences = True intents.members = True +intents.messages = True +intents.presences = True """ -intents = discord.Intents.default() +intents = disnake.Intents.default() -bot = Bot(command_prefix="", intents=intents) # The command prefix is a required argument, but will never be used -slash = SlashCommand(bot, sync_commands=True) +bot = Bot(command_prefix=config["prefix"], intents=intents) # The code in this even is executed when the bot is ready @bot.event async def on_ready(): print(f"Logged in as {bot.user.name}") - print(f"Discord.py API version: {discord.__version__}") + print(f"disnake API version: {disnake.__version__}") print(f"Python version: {platform.python_version()}") print(f"Running on: {platform.system()} {platform.release()} ({os.name})") print("-------------------") @@ -76,7 +75,7 @@ async def on_ready(): @tasks.loop(minutes=1.0) async def status_task(): statuses = ["with you!", "with Krypton!", "with humans!"] - await bot.change_presence(activity=discord.Game(random.choice(statuses))) + await bot.change_presence(activity=disnake.Game(random.choice(statuses))) # Removes the default help command of discord.py to be able to create our custom help command. @@ -96,26 +95,23 @@ async def status_task(): # The code in this event is executed every time someone sends a message, with or without the prefix @bot.event -async def on_message(message: discord.Message): +async def on_message(message: disnake.Message): # Ignores if a command is being executed by a bot or by the bot itself if message.author == bot.user or message.author.bot: return await bot.process_commands(message) -# The code in this event is executed every time a command has been *successfully* executed +# The code in this event is executed every time a slash command has been *successfully* executed @bot.event -async def on_slash_command(ctx: SlashContext): - full_command_name = ctx.name - split = full_command_name.split(" ") - executed_command = str(split[0]) +async def on_slash_command(interaction: ApplicationCommandInteraction): print( - f"Executed {executed_command} command in {ctx.guild.name} (ID: {ctx.guild.id}) by {ctx.author} (ID: {ctx.author.id})") + f"Executed {interaction.data.name} command in {interaction.guild.name} (ID: {interaction.guild.id}) by {interaction.author} (ID: {interaction.author.id})") -# The code in this event is executed every time a valid commands catches an error +# The code in this event is executed every time a valid slash command catches an error @bot.event -async def on_slash_command_error(context: SlashContext, error: Exception): +async def on_slash_command_error(interaction: ApplicationCommandInteraction, error: Exception): if isinstance(error, exceptions.UserBlacklisted): """ The code here will only execute if the error is an instance of 'UserBlacklisted', which can occur when using @@ -123,8 +119,64 @@ async def on_slash_command_error(context: SlashContext, error: Exception): 'hidden=True' will make so that only the user who execute the command can see the message """ + embed = disnake.Embed( + title="Error!", + description="You are blacklisted from using the bot.", + color=0xE02B2B + ) + print("A blacklisted user tried to execute a command.") + return await interaction.send(embed=embed, ephemeral=True) + elif isinstance(error, commands.errors.MissingPermissions): + embed = disnake.Embed( + title="Error!", + description="You are missing the permission(s) `" + ", ".join( + error.missing_permissions) + "` to execute this command!", + color=0xE02B2B + ) print("A blacklisted user tried to execute a command.") - return await context.send("You are blacklisted from using the bot.", hidden=True) + return await interaction.send(embed=embed, ephemeral=True) + raise error + + +# The code in this event is executed every time a normal command has been *successfully* executed +@bot.event +async def on_command_completion(ctx): + fullCommandName = ctx.command.qualified_name + split = fullCommandName.split(" ") + executedCommand = str(split[0]) + print( + f"Executed {executedCommand} command in {ctx.guild.name} (ID: {ctx.message.guild.id}) by {ctx.message.author} (ID: {ctx.message.author.id})") + + +# The code in this event is executed every time a normal valid command catches an error +@bot.event +async def on_command_error(context, error): + if isinstance(error, commands.CommandOnCooldown): + minutes, seconds = divmod(error.retry_after, 60) + hours, minutes = divmod(minutes, 60) + hours = hours % 24 + embed = disnake.Embed( + title="Hey, please slow down!", + description=f"You can use this command again in {f'{round(hours)} hours' if round(hours) > 0 else ''} {f'{round(minutes)} minutes' if round(minutes) > 0 else ''} {f'{round(seconds)} seconds' if round(seconds) > 0 else ''}.", + color=0xE02B2B + ) + await context.send(embed=embed) + elif isinstance(error, commands.MissingPermissions): + embed = disnake.Embed( + title="Error!", + description="You are missing the permission(s) `" + ", ".join( + error.missing_permissions) + "` to execute this command!", + color=0xE02B2B + ) + await context.send(embed=embed) + elif isinstance(error, commands.MissingRequiredArgument): + embed = disnake.Embed( + title="Error!", + description=str(error).capitalize(), + # We need to capitalize because the command arguments have no capital letter in the code. + color=0xE02B2B + ) + await context.send(embed=embed) raise error diff --git a/cogs/fun.py b/cogs/fun.py index ab55bbbf..6563c89f 100644 --- a/cogs/fun.py +++ b/cogs/fun.py @@ -3,17 +3,19 @@ Description: This is a template to create your own discord bot in python. -Version: 3.1.1 +Version: 4.0 """ import json import os +import random import sys import aiohttp -import discord -from discord.ext import commands -from discord_slash import cog_ext, SlashContext +import disnake +from disnake import ApplicationCommandInteraction +from disnake.ext import commands +from disnake.ext.commands import Context from helpers import checks @@ -24,16 +26,128 @@ config = json.load(file) +class Choice(disnake.ui.View): + def __init__(self): + super().__init__() + self.choice = None + + @disnake.ui.button(label="Heads", style=disnake.ButtonStyle.blurple) + async def confirm(self, button: disnake.ui.Button, interaction: disnake.MessageInteraction): + self.choice = button.label.lower() + self.stop() + + @disnake.ui.button(label="Tails", style=disnake.ButtonStyle.blurple) + async def cancel(self, button: disnake.ui.Button, interaction: disnake.MessageInteraction): + self.choice = button.label.lower() + self.stop() + + +class RockPaperScissors(disnake.ui.Select): + def __init__(self): + + options = [ + disnake.SelectOption( + label="Scissors", description="You choose scissors.", emoji="๐Ÿชจ" + ), + disnake.SelectOption( + label="Rock", description="You choose rock.", emoji="๐Ÿงป" + ), + disnake.SelectOption( + label="paper", description="You choose paper.", emoji="โœ‚" + ), + ] + + super().__init__( + placeholder="Choose...", + min_values=1, + max_values=1, + options=options, + ) + + async def callback(self, interaction: disnake.MessageInteraction): + choices = { + "rock": 0, + "paper": 1, + "scissors": 2, + } + user_choice = self.values[0].lower() + user_choice_index = choices[user_choice] + + bot_choice = random.choice(list(choices.keys())) + bot_choice_index = choices[bot_choice] + + result_embed = disnake.Embed(color=0x9C84EF) + result_embed.set_author(name=interaction.author.display_name, icon_url=interaction.author.avatar.url) + + if user_choice_index == bot_choice_index: + result_embed.description = f"**That's a draw!**\nYou've chosen {user_choice} and I've chosen {bot_choice}." + result_embed.colour = 0xF59E42 + elif user_choice_index == 0 and bot_choice_index == 2: + result_embed.description = f"**You won!**\nYou've chosen {user_choice} and I've chosen {bot_choice}." + result_embed.colour = 0x9C84EF + elif user_choice_index == 1 and bot_choice_index == 0: + result_embed.description = f"**You won!**\nYou've chosen {user_choice} and I've chosen {bot_choice}." + result_embed.colour = 0x9C84EF + elif user_choice_index == 2 and bot_choice_index == 1: + result_embed.description = f"**You won!**\nYou've chosen {user_choice} and I've chosen {bot_choice}." + result_embed.colour = 0x9C84EF + else: + result_embed.description = f"**I won!**\nYou've chosen {user_choice} and I've chosen {bot_choice}." + result_embed.colour = 0xE02B2B + await interaction.response.defer() + await interaction.edit_original_message(embed=result_embed, content=None, view=None) + + +class RockPaperScissorsView(disnake.ui.View): + def __init__(self): + super().__init__() + + self.add_item(RockPaperScissors()) + + class Fun(commands.Cog, name="fun"): def __init__(self, bot): self.bot = bot - @cog_ext.cog_slash( + @commands.slash_command( name="randomfact", description="Get a random fact." ) @checks.not_blacklisted() - async def randomfact(self, context: SlashContext): + async def randomfact(self, interaction: ApplicationCommandInteraction): + """ + Get a random fact. + """ + + # This is, for now, only temporary + with open("blacklist.json") as file: + blacklist = json.load(file) + if interaction.author.id in blacklist["ids"]: + return + + # This will prevent your bot from stopping everything when doing a web request - see: https://discordpy.readthedocs.io/en/stable/faq.html#how-do-i-make-a-web-request + async with aiohttp.ClientSession() as session: + async with session.get("https://uselessfacts.jsph.pl/random.json?language=en") as request: + if request.status == 200: + data = await request.json() + embed = disnake.Embed( + description=data["text"], + color=0xD75BF4 + ) + else: + embed = disnake.Embed( + title="Error!", + description="There is something wrong with the API, please try again later", + color=0xE02B2B + ) + await interaction.send(embed=embed) + + @commands.command( + name="randomfact", + description="Get a random fact." + ) + @checks.not_blacklisted() + async def randomfact(self, context: Context): """ Get a random fact. """ @@ -49,15 +163,89 @@ async def randomfact(self, context: SlashContext): async with session.get("https://uselessfacts.jsph.pl/random.json?language=en") as request: if request.status == 200: data = await request.json() - embed = discord.Embed(description=data["text"], color=0xD75BF4) - await context.send(embed=embed) + embed = disnake.Embed( + description=data["text"], + color=0xD75BF4 + ) else: - embed = discord.Embed( + embed = disnake.Embed( title="Error!", description="There is something wrong with the API, please try again later", color=0xE02B2B ) - await context.send(embed=embed) + await context.send(embed=embed) + + @commands.slash_command( + name="coinflip", + description="Make a coin flip, but give your bet before." + ) + @checks.not_blacklisted() + async def coinflip(self, interaction: ApplicationCommandInteraction): + buttons = Choice() + embed = disnake.Embed( + description="What is your bet?", + color=0x9C84EF + ) + await interaction.send(embed=embed, view=buttons) + await buttons.wait() # We wait for the user to click a button. + result = random.choice(["heads", "tails"]) + if buttons.choice == result: + # User guessed correctly + embed = disnake.Embed( + description=f"Correct! You guessed `{buttons.choice}` and I flipped the coin to `{result}`.", + color=0x9C84EF + ) + else: + embed = disnake.Embed( + description=f"Woops! You guessed `{buttons.choice}` and I flipped the coin to `{result}`, better luck next time!", + color=0xE02B2B + ) + await interaction.edit_original_message(embed=embed, view=None) + + @commands.command( + name="coinflip", + description="Make a coin flip, but give your bet before." + ) + @checks.not_blacklisted() + async def coinflip(self, context: Context): + buttons = Choice() + embed = disnake.Embed( + description="What is your bet?", + color=0x9C84EF + ) + message = await context.send(embed=embed, view=buttons) + await buttons.wait() # We wait for the user to click a button. + result = random.choice(["heads", "tails"]) + if buttons.choice == result: + # User guessed correctly + embed = disnake.Embed( + description=f"Correct! You guessed `{buttons.choice}` and I flipped the coin to `{result}`.", + color=0x9C84EF + ) + else: + embed = disnake.Embed( + description=f"Woops! You guessed `{buttons.choice}` and I flipped the coin to `{result}`, better luck next time!", + color=0xE02B2B + ) + await message.edit(embed=embed, view=None) + + @commands.slash_command( + name="rps", + description="Play the rock paper scissors against the bot." + ) + @checks.not_blacklisted() + async def rock_paper_scissors(self, interaction: ApplicationCommandInteraction): + view = RockPaperScissorsView() + await interaction.send("Please make your choice", view=view) + + @commands.command( + name="rps", + description="Play the rock paper scissors against the bot." + ) + @checks.not_blacklisted() + async def rock_paper_scissors(self, context: Context): + view = RockPaperScissorsView() + await context.send("Please make your choice", view=view) def setup(bot): diff --git a/cogs/general.py b/cogs/general.py index 8a553ce4..5da187b6 100644 --- a/cogs/general.py +++ b/cogs/general.py @@ -3,7 +3,7 @@ Description: This is a template to create your own discord bot in python. -Version: 3.1.1 +Version: 4.0 """ import json @@ -13,10 +13,10 @@ import sys import aiohttp -import discord -from discord.ext import commands -from discord_slash import cog_ext, SlashContext -from discord_slash.utils.manage_commands import create_option +import disnake +from disnake import ApplicationCommandInteraction, Option, OptionType +from disnake.ext import commands +from disnake.ext.commands import Context from helpers import checks @@ -31,25 +31,61 @@ class General(commands.Cog, name="general"): def __init__(self, bot): self.bot = bot - @cog_ext.cog_slash( + @commands.slash_command( name="botinfo", description="Get some useful (or not) information about the bot.", ) @checks.not_blacklisted() - async def botinfo(self, context: SlashContext): + async def botinfo(self, interaction: ApplicationCommandInteraction): """ Get some useful (or not) information about the bot. """ - embed = discord.Embed( + embed = disnake.Embed( description="Used [Krypton's](https://krypt0n.co.uk) template", - color=0x42F56C + color=0x9C84EF ) embed.set_author( name="Bot Information" ) embed.add_field( name="Owner:", - value="Krypton#2188", + value="Krypton#7331", + inline=True + ) + embed.add_field( + name="Python Version:", + value=f"{platform.python_version()}", + inline=True + ) + embed.add_field( + name="Prefix:", + value=f"/ (Slash Commands)", + inline=False + ) + embed.set_footer( + text=f"Requested by {interaction.author}" + ) + await interaction.send(embed=embed) + + @commands.command( + name="botinfo", + description="Get some useful (or not) information about the bot.", + ) + @checks.not_blacklisted() + async def botinfo(self, context: Context): + """ + Get some useful (or not) information about the bot. + """ + embed = disnake.Embed( + description="Used [Krypton's](https://krypt0n.co.uk) template", + color=0x9C84EF + ) + embed.set_author( + name="Bot Information" + ) + embed.add_field( + name="Owner:", + value="Krypton#7331", inline=True ) embed.add_field( @@ -67,155 +103,242 @@ async def botinfo(self, context: SlashContext): ) await context.send(embed=embed) - @cog_ext.cog_slash( + @commands.slash_command( + name="serverinfo", + description="Get some useful (or not) information about the server.", + ) + @checks.not_blacklisted() + async def serverinfo(self, interaction: ApplicationCommandInteraction): + """ + Get some useful (or not) information about the server. + """ + roles = [role.name for role in interaction.guild.roles] + if len(roles) > 50: + roles = roles[:50] + roles.append(f">>>> Displaying[50/{len(roles)}] Roles") + roles = ", ".join(roles) + + embed = disnake.Embed( + title="**Server Name:**", + description=f"{interaction.guild}", + color=0x9C84EF + ) + embed.set_thumbnail( + url=interaction.guild.icon.url + ) + embed.add_field( + name="Server ID", + value=interaction.guild.id + ) + embed.add_field( + name="Member Count", + value=interaction.guild.member_count + ) + embed.add_field( + name="Text/Voice Channels", + value=f"{len(interaction.guild.channels)}" + ) + embed.add_field( + name=f"Roles ({len(interaction.guild.roles)})", + value=roles + ) + embed.set_footer( + text=f"Created at: {interaction.guild.created_at}" + ) + await interaction.send(embed=embed) + + @commands.command( name="serverinfo", description="Get some useful (or not) information about the server.", ) @checks.not_blacklisted() - async def serverinfo(self, context: SlashContext): + async def serverinfo(self, context: Context): """ Get some useful (or not) information about the server. """ - server = context.guild - roles = [x.name for x in server.roles] - role_length = len(roles) - if role_length > 50: + roles = [role.name for role in context.guild.roles] + if len(roles) > 50: roles = roles[:50] roles.append(f">>>> Displaying[50/{len(roles)}] Roles") roles = ", ".join(roles) - channels = len(server.channels) - time = str(server.created_at) - time = time.split(" ") - time = time[0] - embed = discord.Embed( + embed = disnake.Embed( title="**Server Name:**", - description=f"{server}", - color=0x42F56C + description=f"{context.guild}", + color=0x9C84EF ) embed.set_thumbnail( - url=server.icon_url + url=context.guild.icon.url ) embed.add_field( name="Server ID", - value=server.id + value=context.guild.id ) embed.add_field( name="Member Count", - value=server.member_count + value=context.guild.member_count ) embed.add_field( name="Text/Voice Channels", - value=f"{channels}" + value=f"{len(context.guild.channels)}" ) embed.add_field( - name=f"Roles ({role_length})", + name=f"Roles ({len(context.guild.roles)})", value=roles ) embed.set_footer( - text=f"Created at: {time}" + text=f"Created at: {context.guild.created_at}" ) await context.send(embed=embed) - @cog_ext.cog_slash( + @commands.slash_command( name="ping", description="Check if the bot is alive.", ) @checks.not_blacklisted() - async def ping(self, context: SlashContext): + async def ping(self, interaction: ApplicationCommandInteraction): """ Check if the bot is alive. """ - embed = discord.Embed( + embed = disnake.Embed( title="๐Ÿ“ Pong!", description=f"The bot latency is {round(self.bot.latency * 1000)}ms.", - color=0x42F56C + color=0x9C84EF + ) + await interaction.send(embed=embed) + + @commands.command( + name="ping", + description="Check if the bot is alive.", + ) + @checks.not_blacklisted() + async def ping(self, context: Context): + """ + Check if the bot is alive. + """ + embed = disnake.Embed( + title="๐Ÿ“ Pong!", + description=f"The bot latency is {round(self.bot.latency * 1000)}ms.", + color=0x9C84EF ) await context.send(embed=embed) - @cog_ext.cog_slash( + @commands.slash_command( name="invite", description="Get the invite link of the bot to be able to invite it.", ) @checks.not_blacklisted() - async def invite(self, context: SlashContext): + async def invite(self, interaction: ApplicationCommandInteraction): """ Get the invite link of the bot to be able to invite it. """ - embed = discord.Embed( - description=f"Invite me by clicking [here](https://discordapp.com/oauth2/authorize?&client_id={config['application_id']}&scope=bot&permissions=470150263).", + embed = disnake.Embed( + description=f"Invite me by clicking [here](https://discordapp.com/oauth2/authorize?&client_id={config['application_id']}&scope=bot+applications.commands&permissions={config['permissions']}).", + color=0xD75BF4 + ) + try: + # To know what permissions to give to your bot, please see here: https://discordapi.com/permissions.html and remember to not give Administrator permissions. + await interaction.author.send(embed=embed) + await interaction.send("I sent you a private message!") + except disnake.Forbidden: + await interaction.send(embed=embed) + + @commands.command( + name="invite", + description="Get the invite link of the bot to be able to invite it.", + ) + @checks.not_blacklisted() + async def invite(self, context: Context): + """ + Get the invite link of the bot to be able to invite it. + """ + embed = disnake.Embed( + description=f"Invite me by clicking [here](https://discordapp.com/oauth2/authorize?&client_id={config['application_id']}&scope=bot+applications.commands&permissions={config['permissions']}).", color=0xD75BF4 ) try: # To know what permissions to give to your bot, please see here: https://discordapi.com/permissions.html and remember to not give Administrator permissions. await context.author.send(embed=embed) await context.send("I sent you a private message!") - except discord.Forbidden: + except disnake.Forbidden: await context.send(embed=embed) - @cog_ext.cog_slash( + @commands.slash_command( name="server", description="Get the invite link of the discord server of the bot for some support.", ) @checks.not_blacklisted() - async def server(self, context: SlashContext): + async def server(self, interaction: ApplicationCommandInteraction): """ Get the invite link of the discord server of the bot for some support. """ - embed = discord.Embed( + embed = disnake.Embed( + description=f"Join the support server for the bot by clicking [here](https://discord.gg/mTBrXyWxAF).", + color=0xD75BF4 + ) + try: + await interaction.author.send(embed=embed) + await interaction.send("I sent you a private message!") + except disnake.Forbidden: + await interaction.send(embed=embed) + + @commands.command( + name="server", + description="Get the invite link of the discord server of the bot for some support.", + ) + @checks.not_blacklisted() + async def server(self, context: Context): + """ + Get the invite link of the discord server of the bot for some support. + """ + embed = disnake.Embed( description=f"Join the support server for the bot by clicking [here](https://discord.gg/mTBrXyWxAF).", color=0xD75BF4 ) try: await context.author.send(embed=embed) await context.send("I sent you a private message!") - except discord.Forbidden: + except disnake.Forbidden: await context.send(embed=embed) - @cog_ext.cog_slash( - name="poll", - description="Create a poll where members can vote.", + @commands.slash_command( + name="8ball", + description="Ask any question to the bot.", options=[ - create_option( - name="title", - description="The title of the poll.", - option_type=3, + Option( + name="question", + description="The question you want to ask.", + type=OptionType.string, required=True ) ], ) @checks.not_blacklisted() - async def poll(self, context: SlashContext, title: str): + async def eight_ball(self, interaction: ApplicationCommandInteraction, question: str): """ - Create a poll where members can vote. + Ask any question to the bot. """ - embed = discord.Embed( - title="A new poll has been created!", - description=f"{title}", - color=0x42F56C + answers = ['It is certain.', 'It is decidedly so.', 'You may rely on it.', 'Without a doubt.', + 'Yes - definitely.', 'As I see, yes.', 'Most likely.', 'Outlook good.', 'Yes.', + 'Signs point to yes.', 'Reply hazy, try again.', 'Ask again later.', 'Better not tell you now.', + 'Cannot predict now.', 'Concentrate and ask again later.', 'Don\'t count on it.', 'My reply is no.', + 'My sources say no.', 'Outlook not so good.', 'Very doubtful.'] + embed = disnake.Embed( + title="**My Answer:**", + description=f"{answers[random.randint(0, len(answers) - 1)]}", + color=0x9C84EF ) embed.set_footer( - text=f"Poll created by: {context.author} โ€ข React to vote!" + text=f"The question was: {question}" ) - embed_message = await context.send(embed=embed) - await embed_message.add_reaction("๐Ÿ‘") - await embed_message.add_reaction("๐Ÿ‘Ž") - await embed_message.add_reaction("๐Ÿคท") + await interaction.send(embed=embed) - @cog_ext.cog_slash( + @commands.command( name="8ball", description="Ask any question to the bot.", - options=[ - create_option( - name="question", - description="The question you want to ask.", - option_type=3, - required=True - ) - ], ) @checks.not_blacklisted() - async def eight_ball(self, context: SlashContext, question: str): + async def eight_ball(self, context: Context, *, question: str): """ Ask any question to the bot. """ @@ -224,37 +347,71 @@ async def eight_ball(self, context: SlashContext, question: str): 'Signs point to yes.', 'Reply hazy, try again.', 'Ask again later.', 'Better not tell you now.', 'Cannot predict now.', 'Concentrate and ask again later.', 'Don\'t count on it.', 'My reply is no.', 'My sources say no.', 'Outlook not so good.', 'Very doubtful.'] - embed = discord.Embed( + embed = disnake.Embed( title="**My Answer:**", - description=f"{answers[random.randint(0, len(answers))]}", - color=0x42F56C + description=f"{answers[random.randint(0, len(answers) - 1)]}", + color=0x9C84EF ) embed.set_footer( text=f"The question was: {question}" ) await context.send(embed=embed) - @cog_ext.cog_slash( + @commands.slash_command( name="bitcoin", description="Get the current price of bitcoin.", ) @checks.not_blacklisted() - async def bitcoin(self, context): + async def bitcoin(self, interaction: ApplicationCommandInteraction): """ Get the current price of bitcoin. """ - url = "https://api.coindesk.com/v1/bpi/currentprice/BTC.json" - # Async HTTP request + # This will prevent your bot from stopping everything when doing a web request - see: https://discordpy.readthedocs.io/en/stable/faq.html#how-do-i-make-a-web-request async with aiohttp.ClientSession() as session: - raw_response = await session.get(url) - response = await raw_response.text() - response = json.loads(response) - embed = discord.Embed( - title=":information_source: Info", - description=f"Bitcoin price is: ${response['bpi']['USD']['rate']}", - color=0x42F56C - ) - await context.send(embed=embed) + async with session.get("https://api.coindesk.com/v1/bpi/currentprice/BTC.json") as request: + if request.status == 200: + data = await request.json( + content_type="application/javascript") # For some reason the returned content is of type JavaScript + embed = disnake.Embed( + title="Bitcoin price", + description=f"The current price is {data['bpi']['USD']['rate']} :dollar:", + color=0x9C84EF + ) + else: + embed = disnake.Embed( + title="Error!", + description="There is something wrong with the API, please try again later", + color=0xE02B2B + ) + await interaction.send(embed=embed) + + @commands.command( + name="bitcoin", + description="Get the current price of bitcoin.", + ) + @checks.not_blacklisted() + async def bitcoin(self, context: Context): + """ + Get the current price of bitcoin. + """ + # This will prevent your bot from stopping everything when doing a web request - see: https://discordpy.readthedocs.io/en/stable/faq.html#how-do-i-make-a-web-request + async with aiohttp.ClientSession() as session: + async with session.get("https://api.coindesk.com/v1/bpi/currentprice/BTC.json") as request: + if request.status == 200: + data = await request.json( + content_type="application/javascript") # For some reason the returned content is of type JavaScript + embed = disnake.Embed( + title="Bitcoin price", + description=f"The current price is {data['bpi']['USD']['rate']} :dollar:", + color=0x9C84EF + ) + else: + embed = disnake.Embed( + title="Error!", + description="There is something wrong with the API, please try again later", + color=0xE02B2B + ) + await context.send(embed=embed) def setup(bot): diff --git a/cogs/moderation.py b/cogs/moderation.py index f7f9c07d..e831df29 100644 --- a/cogs/moderation.py +++ b/cogs/moderation.py @@ -3,17 +3,17 @@ Description: This is a template to create your own discord bot in python. -Version: 3.1.1 +Version: 4.0 """ import json import os import sys -import discord -from discord.ext import commands -from discord_slash import cog_ext, SlashContext -from discord_slash.utils.manage_commands import create_option +import disnake +from disnake import ApplicationCommandInteraction, Option, OptionType +from disnake.ext import commands +from disnake.ext.commands import Context from helpers import checks @@ -28,40 +28,78 @@ class Moderation(commands.Cog, name="moderation"): def __init__(self, bot): self.bot = bot - @cog_ext.cog_slash( + @commands.slash_command( name='kick', description="Kick a user out of the server.", options=[ - create_option( + Option( name="user", description="The user you want to kick.", - option_type=6, + type=OptionType.user, required=True ), - create_option( + Option( name="reason", description="The reason you kicked the user.", - option_type=3, + type=OptionType.string, required=False ) - ], + ] ) + @commands.has_permissions(kick_members=True) @checks.not_blacklisted() - async def kick(self, context: SlashContext, user: discord.User, reason: str = "Not specified"): + async def kick(self, interaction: ApplicationCommandInteraction, user: disnake.User, reason: str = "Not specified"): """ Kick a user out of the server. """ - author = context.guild.get_member(context.author_id) or await context.guild.fetch_member(context.author_id) - if not author.guild_permissions.kick_members: - embed = discord.Embed( + member = interaction.guild.get_member(user.id) or await interaction.guild.fetch_member(user.id) + if member.guild_permissions.administrator: + embed = disnake.Embed( title="Error!", - description="You don't have enough permissions to kick this user.", + description="User has Admin permissions.", color=0xE02B2B ) - return await context.send(embed=embed) - member = context.guild.get_member(user.id) or await context.guild.fetch_member(user.id) + await interaction.send(embed=embed) + else: + try: + embed = disnake.Embed( + title="User Kicked!", + description=f"**{member}** was kicked by **{interaction.author}**!", + color=0x9C84EF + ) + embed.add_field( + name="Reason:", + value=reason + ) + await interaction.send(embed=embed) + try: + await member.send( + f"You were kicked by **{interaction.author}**!\nReason: {reason}" + ) + except disnake.Forbidden: + # Couldn't send a message in the private messages of the user + pass + await member.kick(reason=reason) + except: + embed = disnake.Embed( + title="Error!", + description="An error occurred while trying to kick the user. Make sure my role is above the role of the user you want to kick.", + color=0xE02B2B + ) + await interaction.send(embed=embed) + + @commands.command( + name='kick', + description="Kick a user out of the server.", + ) + @commands.has_permissions(kick_members=True) + @checks.not_blacklisted() + async def kick(self, context: Context, member: disnake.Member, *, reason: str = "Not specified"): + """ + Kick a user out of the server. + """ if member.guild_permissions.administrator: - embed = discord.Embed( + embed = disnake.Embed( title="Error!", description="User has Admin permissions.", color=0xE02B2B @@ -69,11 +107,10 @@ async def kick(self, context: SlashContext, user: discord.User, reason: str = "N await context.send(embed=embed) else: try: - await member.kick(reason=reason) - embed = discord.Embed( + embed = disnake.Embed( title="User Kicked!", description=f"**{member}** was kicked by **{context.author}**!", - color=0x42F56C + color=0x9C84EF ) embed.add_field( name="Reason:", @@ -84,161 +121,241 @@ async def kick(self, context: SlashContext, user: discord.User, reason: str = "N await member.send( f"You were kicked by **{context.author}**!\nReason: {reason}" ) - except: + except disnake.Forbidden: + # Couldn't send a message in the private messages of the user pass + await member.kick(reason=reason) except: - embed = discord.Embed( + embed = disnake.Embed( title="Error!", description="An error occurred while trying to kick the user. Make sure my role is above the role of the user you want to kick.", color=0xE02B2B ) - await context.message.channel.send(embed=embed) + await context.send(embed=embed) - @cog_ext.cog_slash( + @commands.slash_command( name='nick', description="Change the nickname of a user on a server.", options=[ - create_option( + Option( name="user", description="The user you want to change the nickname.", - option_type=6, + type=OptionType.user, required=True ), - create_option( + Option( name="nickname", description="The new nickname of the user.", - option_type=3, + type=OptionType.string, required=False ) ], ) + @commands.has_permissions(manage_nicknames=True) @checks.not_blacklisted() - async def nick(self, context: SlashContext, user: discord.User, nickname: str = None): + async def nick(self, interaction: ApplicationCommandInteraction, user: disnake.User, nickname: str = None): """ Change the nickname of a user on a server. """ - author = context.guild.get_member(context.author_id) or await context.guild.fetch_member(context.author_id) - if not author.guild_permissions.manage_nicknames: - embed = discord.Embed( + member = interaction.guild.get_member(user.id) or await interaction.guild.fetch_member(user.id) + try: + await member.edit(nick=nickname) + embed = disnake.Embed( + title="Changed Nickname!", + description=f"**{member}'s** new nickname is **{nickname}**!", + color=0x9C84EF + ) + await interaction.send(embed=embed) + except: + embed = disnake.Embed( title="Error!", - description="You don't have enough permissions to change the nickname of this user.", + description="An error occurred while trying to change the nickname of the user. Make sure my role is above the role of the user you want to change the nickname.", color=0xE02B2B ) - return await context.send(embed=embed) - member = context.guild.get_member(user.id) or await context.guild.fetch_member(user.id) + await interaction.send(embed=embed) + + @commands.command( + name='nick', + description="Change the nickname of a user on a server.", + ) + @commands.has_permissions(manage_nicknames=True) + @checks.not_blacklisted() + async def nick(self, context: Context, member: disnake.Member, *, nickname: str = None): + """ + Change the nickname of a user on a server. + """ try: await member.edit(nick=nickname) - embed = discord.Embed( + embed = disnake.Embed( title="Changed Nickname!", description=f"**{member}'s** new nickname is **{nickname}**!", - color=0x42F56C + color=0x9C84EF ) await context.send(embed=embed) except: - embed = discord.Embed( + embed = disnake.Embed( title="Error!", description="An error occurred while trying to change the nickname of the user. Make sure my role is above the role of the user you want to change the nickname.", color=0xE02B2B ) - await context.message.channel.send(embed=embed) + await context.send(embed=embed) - @cog_ext.cog_slash( + @commands.slash_command( name='ban', description="Bans a user from the server.", options=[ - create_option( + Option( name="user", description="The user you want to ban.", - option_type=6, + type=OptionType.user, required=True ), - create_option( + Option( name="reason", description="The reason you banned the user.", - option_type=3, + type=OptionType.string, required=False ) ], ) + @commands.has_permissions(ban_members=True) @checks.not_blacklisted() - async def ban(self, context, user: discord.User, reason: str = "Not specified"): + async def ban(self, interaction: ApplicationCommandInteraction, user: disnake.User, reason: str = "Not specified"): """ Bans a user from the server. """ - author = context.guild.get_member(context.author_id) or await context.guild.fetch_member(context.author_id) - if not author.guild_permissions.ban_members: - embed = discord.Embed( + member = interaction.guild.get_member(user.id) or await interaction.guild.fetch_member(user.id) + try: + if member.guild_permissions.administrator: + embed = disnake.Embed( + title="Error!", + description="User has Admin permissions.", + color=0xE02B2B + ) + await interaction.send(embed=embed) + else: + embed = disnake.Embed( + title="User Banned!", + description=f"**{member}** was banned by **{interaction.author}**!", + color=0x9C84EF + ) + embed.add_field( + name="Reason:", + value=reason + ) + await interaction.send(embed=embed) + try: + await member.send(f"You were banned by **{interaction.author}**!\nReason: {reason}") + except disnake.Forbidden: + # Couldn't send a message in the private messages of the user + pass + await member.ban(reason=reason) + except: + embed = disnake.Embed( title="Error!", - description="You don't have enough permissions to ban this user.", + description="An error occurred while trying to ban the user. Make sure my role is above the role of the user you want to ban.", color=0xE02B2B ) - return await context.send(embed=embed) - member = context.guild.get_member(user.id) or await context.guild.fetch_member(user.id) + await interaction.send(embed=embed) + + @commands.command( + name='ban', + description="Bans a user from the server.", + ) + @commands.has_permissions(ban_members=True) + @checks.not_blacklisted() + async def ban(self, context: Context, member: disnake.Member, *, reason: str = "Not specified"): + """ + Bans a user from the server. + """ try: if member.guild_permissions.administrator: - embed = discord.Embed( + embed = disnake.Embed( title="Error!", description="User has Admin permissions.", color=0xE02B2B ) await context.send(embed=embed) else: - await member.ban(reason=reason) - embed = discord.Embed( + embed = disnake.Embed( title="User Banned!", description=f"**{member}** was banned by **{context.author}**!", - color=0x42F56C + color=0x9C84EF ) embed.add_field( name="Reason:", value=reason ) await context.send(embed=embed) - await member.send(f"You were banned by **{context.author}**!\nReason: {reason}") + try: + await member.send(f"You were banned by **{context.author}**!\nReason: {reason}") + except disnake.Forbidden: + # Couldn't send a message in the private messages of the user + pass + await member.ban(reason=reason) except: - embed = discord.Embed( + embed = disnake.Embed( title="Error!", description="An error occurred while trying to ban the user. Make sure my role is above the role of the user you want to ban.", color=0xE02B2B ) await context.send(embed=embed) - @cog_ext.cog_slash( + @commands.slash_command( name='warn', - description="Warns a user from the server.", + description="Warns a user in the server.", options=[ - create_option( + Option( name="user", description="The user you want to warn.", - option_type=6, + type=OptionType.user, required=True ), - create_option( + Option( name="reason", description="The reason you warned the user.", - option_type=3, + type=OptionType.string, required=False ) ], ) + @commands.has_permissions(manage_messages=True) @checks.not_blacklisted() - async def warn(self, context, user: discord.User, reason: str = "Not specified"): + async def warn(self, interaction: ApplicationCommandInteraction, user: disnake.User, reason: str = "Not specified"): """ Warns a user in his private messages. """ - author = context.guild.get_member(context.author_id) or await context.guild.fetch_member(context.author_id) - if not author.guild_permissions.manage_messages: - embed = discord.Embed( - title="Error!", - description="You don't have enough permissions to warn this user.", - color=0xE02B2B - ) - return await context.send(embed=embed) - member = context.guild.get_member(user.id) or await context.guild.fetch_member(user.id) - embed = discord.Embed( + member = interaction.guild.get_member(user.id) or await interaction.guild.fetch_member(user.id) + embed = disnake.Embed( + title="User Warned!", + description=f"**{member}** was warned by **{interaction.author}**!", + color=0x9C84EF + ) + embed.add_field( + name="Reason:", + value=reason + ) + await interaction.send(embed=embed) + try: + await member.send(f"You were warned by **{interaction.author}**!\nReason: {reason}") + except disnake.Forbidden: + # Couldn't send a message in the private messages of the user + await interaction.send(f"{member.mention}, you were warned by **{interaction.author}**!\nReason: {reason}") + + @commands.command( + name='warn', + description="Warns a user in the server.", + ) + @commands.has_permissions(manage_messages=True) + @checks.not_blacklisted() + async def warn(self, context: Context, member: disnake.Member, *, reason: str = "Not specified"): + """ + Warns a user in his private messages. + """ + embed = disnake.Embed( title="User Warned!", description=f"**{member}** was warned by **{context.author}**!", - color=0x42F56C + color=0x9C84EF ) embed.add_field( name="Reason:", @@ -247,57 +364,69 @@ async def warn(self, context, user: discord.User, reason: str = "Not specified") await context.send(embed=embed) try: await member.send(f"You were warned by **{context.author}**!\nReason: {reason}") - except: - pass + except disnake.Forbidden: + # Couldn't send a message in the private messages of the user + await context.send(f"{member.mention}, you were warned by **{context.author}**!\nReason: {reason}") - @cog_ext.cog_slash( + @commands.slash_command( name='purge', description="Delete a number of messages.", options=[ - create_option( + Option( name="amount", - description="The amount of messages you want to delete.", - option_type=4, - required=True + description="The amount of messages you want to delete. (Must be between 1 and 100.)", + type=OptionType.integer, + required=True, + min_value=1, + max_value=100 ) ], ) + @commands.has_guild_permissions(manage_messages=True) @checks.not_blacklisted() - async def purge(self, context, amount: int): + async def purge(self, interaction: ApplicationCommandInteraction, amount: int): + """ + Delete a number of messages. + """ + purged_messages = await interaction.channel.purge(limit=amount) + embed = disnake.Embed( + title="Chat Cleared!", + description=f"**{interaction.author}** cleared **{len(purged_messages)}** messages!", + color=0x9C84EF + ) + await interaction.send(embed=embed) + + @commands.command( + name='purge', + description="Delete a number of messages.", + ) + @commands.has_guild_permissions(manage_messages=True) + @checks.not_blacklisted() + async def purge(self, context: Context, amount: int): """ Delete a number of messages. """ - author = context.guild.get_member(context.author_id) or await context.guild.fetch_member(context.author_id) - if not author.guild_permissions.manage_messages or not author.guild_permissions.manage_channels: - embed = discord.Embed( - title="Error!", - description="You don't have enough permissions purge the chat.", - color=0xE02B2B - ) - return await context.send(embed=embed) try: amount = int(amount) except: - embed = discord.Embed( + embed = disnake.Embed( title="Error!", description=f"`{amount}` is not a valid number.", color=0xE02B2B ) - await context.send(embed=embed) - return + return await context.send(embed=embed) if amount < 1: - embed = discord.Embed( + embed = disnake.Embed( title="Error!", description=f"`{amount}` is not a valid number.", color=0xE02B2B ) - await context.send(embed=embed) - return + return await context.send(embed=embed) purged_messages = await context.channel.purge(limit=amount) - embed = discord.Embed( + embed = disnake.Embed( title="Chat Cleared!", description=f"**{context.author}** cleared **{len(purged_messages)}** messages!", - color=0x42F56C + color=0x9C84EF ) await context.send(embed=embed) diff --git a/cogs/owner.py b/cogs/owner.py index 92c9e1a1..fb77bf09 100644 --- a/cogs/owner.py +++ b/cogs/owner.py @@ -3,17 +3,17 @@ Description: This is a template to create your own discord bot in python. -Version: 3.1.1 +Version: 4.0 """ import json import os import sys -import discord -from discord.ext import commands -from discord_slash import cog_ext, SlashContext -from discord_slash.utils.manage_commands import create_option +import disnake +from disnake import ApplicationCommandInteraction, Option, OptionType +from disnake.ext import commands +from disnake.ext.commands import Context from helpers import json_manager, checks @@ -28,98 +28,150 @@ class Owner(commands.Cog, name="owner"): def __init__(self, bot): self.bot = bot - @cog_ext.cog_slash( + @commands.slash_command( name="shutdown", description="Make the bot shutdown.", ) @checks.is_owner() - async def shutdown(self, context: SlashContext): + async def shutdown(self, interaction: ApplicationCommandInteraction): """ - Make the bot shutdown. + Makes the bot shutdown. """ - embed = discord.Embed( + embed = disnake.Embed( description="Shutting down. Bye! :wave:", - color=0x42F56C + color=0x9C84EF + ) + await interaction.send(embed=embed) + await self.bot.close() + + @commands.command( + name="shutdown", + description="Make the bot shutdown.", + ) + @checks.is_owner() + async def shutdown(self, context: Context): + """ + Makes the bot shutdown. + """ + embed = disnake.Embed( + description="Shutting down. Bye! :wave:", + color=0x9C84EF ) await context.send(embed=embed) await self.bot.close() - @cog_ext.cog_slash( + @commands.slash_command( name="say", description="The bot will say anything you want.", options=[ - create_option( + Option( name="message", description="The message you want me to repeat.", - option_type=3, + type=OptionType.string, required=True ) ], ) @checks.is_owner() - async def say(self, context, message: str): + async def say(self, interaction: ApplicationCommandInteraction, message: str): + """ + The bot will say anything you want. + """ + await interaction.send(message) + + @commands.command( + name="say", + description="The bot will say anything you want.", + ) + @checks.is_owner() + async def say(self, context: Context, *, message: str): """ The bot will say anything you want. """ await context.send(message) - @cog_ext.cog_slash( + @commands.slash_command( name="embed", description="The bot will say anything you want, but within embeds.", options=[ - create_option( + Option( name="message", description="The message you want me to repeat.", - option_type=3, + type=OptionType.string, required=True ) ], ) @checks.is_owner() - async def embed(self, context, message: str): + async def embed(self, interaction: ApplicationCommandInteraction, message: str): """ The bot will say anything you want, but within embeds. """ - embed = discord.Embed( + embed = disnake.Embed( description=message, - color=0x42F56C + color=0x9C84EF + ) + await interaction.send(embed=embed) + + @commands.command( + name="embed", + description="The bot will say anything you want, but within embeds.", + ) + @checks.is_owner() + async def embed(self, context: Context, *, message: str): + """ + The bot will say anything you want, but within embeds. + """ + embed = disnake.Embed( + description=message, + color=0x9C84EF ) await context.send(embed=embed) - @cog_ext.cog_slash( + @commands.slash_command( name="blacklist", description="Get the list of all blacklisted users.", ) @checks.is_owner() - async def blacklist(self, context: SlashContext): + async def blacklist(self, interaction: ApplicationCommandInteraction): + """ + Lets you add or remove a user from not being able to use the bot. + """ + pass + + @commands.group( + name="blacklist" + ) + async def blacklist_normal(self, + context: Context): # Here we need to rename the function name because of sub commands. """ Lets you add or remove a user from not being able to use the bot. """ if context.invoked_subcommand is None: with open("blacklist.json") as file: blacklist = json.load(file) - embed = discord.Embed( + embed = disnake.Embed( title=f"There are currently {len(blacklist['ids'])} blacklisted IDs", description=f"{', '.join(str(id) for id in blacklist['ids'])}", - color=0x0000FF + color=0x9C84EF ) await context.send(embed=embed) - @cog_ext.cog_subcommand( + @blacklist.sub_command( base="blacklist", name="add", description="Lets you add a user from not being able to use the bot.", options=[ - create_option( + Option( name="user", description="The user you want to add to the blacklist.", - option_type=6, + type=OptionType.user, required=True ) ], ) @checks.is_owner() - async def blacklist_add(self, context: SlashContext, user: discord.User = None): + async def blacklist_add(self, interaction: ApplicationCommandInteraction, user: disnake.User = None): """ Lets you add a user from not being able to use the bot. """ @@ -128,81 +180,147 @@ async def blacklist_add(self, context: SlashContext, user: discord.User = None): with open("blacklist.json") as file: blacklist = json.load(file) if user_id in blacklist['ids']: - embed = discord.Embed( + embed = disnake.Embed( title="Error!", description=f"**{user.name}** is already in the blacklist.", color=0xE02B2B ) - await context.send(embed=embed) - return + return await interaction.send(embed=embed) json_manager.add_user_to_blacklist(user_id) - embed = discord.Embed( + embed = disnake.Embed( title="User Blacklisted", description=f"**{user.name}** has been successfully added to the blacklist", - color=0x42F56C + color=0x9C84EF ) with open("blacklist.json") as file: blacklist = json.load(file) embed.set_footer( text=f"There are now {len(blacklist['ids'])} users in the blacklist" ) - await context.send(embed=embed) + await interaction.send(embed=embed) except Exception as exception: - embed = discord.Embed( + embed = disnake.Embed( title="Error!", description=f"An unknown error occurred when trying to add **{user.name}** to the blacklist.", color=0xE02B2B ) - await context.send(embed=embed) + await interaction.send(embed=embed) print(exception) - @cog_ext.cog_subcommand( + @blacklist_normal.command( + name="add" + ) + async def blacklist_add(self, context: Context, member: disnake.Member = None): + """ + Lets you add a user from not being able to use the bot. + """ + try: + user_id = member.id + with open("blacklist.json") as file: + blacklist = json.load(file) + if user_id in blacklist['ids']: + embed = disnake.Embed( + title="Error!", + description=f"**{member.name}** is already in the blacklist.", + color=0xE02B2B + ) + return await context.send(embed=embed) + json_manager.add_user_to_blacklist(user_id) + embed = disnake.Embed( + title="User Blacklisted", + description=f"**{member.name}** has been successfully added to the blacklist", + color=0x9C84EF + ) + with open("blacklist.json") as file: + blacklist = json.load(file) + embed.set_footer( + text=f"There are now {len(blacklist['ids'])} users in the blacklist" + ) + await context.send(embed=embed) + except: + embed = disnake.Embed( + title="Error!", + description=f"An unknown error occurred when trying to add **{member.name}** to the blacklist.", + color=0xE02B2B + ) + await context.send(embed=embed) + + @blacklist.sub_command( base="blacklist", name="remove", description="Lets you remove a user from not being able to use the bot.", options=[ - create_option( + Option( name="user", description="The user you want to remove from the blacklist.", - option_type=6, + type=OptionType.user, required=True ) ], ) @checks.is_owner() - async def blacklist_remove(self, context, user: discord.User = None): + async def blacklist_remove(self, interaction: ApplicationCommandInteraction, user: disnake.User = None): """ Lets you remove a user from not being able to use the bot. """ try: json_manager.remove_user_from_blacklist(user.id) - embed = discord.Embed( + embed = disnake.Embed( title="User removed from blacklist", description=f"**{user.name}** has been successfully removed from the blacklist", - color=0x42F56C + color=0x9C84EF ) with open("blacklist.json") as file: blacklist = json.load(file) embed.set_footer( text=f"There are now {len(blacklist['ids'])} users in the blacklist" ) - await context.send(embed=embed) + await interaction.send(embed=embed) except ValueError: - embed = discord.Embed( + embed = disnake.Embed( title="Error!", description=f"**{user.name}** is not in the blacklist.", color=0xE02B2B ) - await context.send(embed=embed) + await interaction.send(embed=embed) except Exception as exception: - embed = discord.Embed( + embed = disnake.Embed( title="Error!", description=f"An unknown error occurred when trying to add **{user.name}** to the blacklist.", color=0xE02B2B ) - await context.send(embed=embed) + await interaction.send(embed=embed) print(exception) + @blacklist_normal.command( + name="remove" + ) + async def blacklist_remove(self, context, member: disnake.Member = None): + """ + Lets you remove a user from not being able to use the bot. + """ + try: + user_id = member.id + json_manager.remove_user_from_blacklist(user_id) + embed = disnake.Embed( + title="User removed from blacklist", + description=f"**{member.name}** has been successfully removed from the blacklist", + color=0x9C84EF + ) + with open("blacklist.json") as file: + blacklist = json.load(file) + embed.set_footer( + text=f"There are now {len(blacklist['ids'])} users in the blacklist" + ) + await context.send(embed=embed) + except: + embed = disnake.Embed( + title="Error!", + description=f"**{member.name}** is not in the blacklist.", + color=0xE02B2B + ) + await context.send(embed=embed) + def setup(bot): bot.add_cog(Owner(bot)) diff --git a/cogs/template.py b/cogs/template.py index 8b3c8b38..b1ae2328 100644 --- a/cogs/template.py +++ b/cogs/template.py @@ -3,15 +3,16 @@ Description: This is a template to create your own discord bot in python. -Version: 3.1.1 +Version: 4.0 """ import json import os import sys -from discord.ext import commands -from discord_slash import cog_ext, SlashContext +from disnake import ApplicationCommandInteraction +from disnake.ext import commands +from disnake.ext.commands import Context from helpers import checks @@ -29,7 +30,7 @@ def __init__(self, bot): self.bot = bot # Here you can just add your own commands, you'll always need to provide "self" as first parameter. - @cog_ext.cog_slash( + @commands.slash_command( name="testcommand", description="This is a testing command that does nothing.", ) @@ -37,15 +38,29 @@ def __init__(self, bot): @checks.not_blacklisted() # This will only allow owners of the bot to execute the command -> config.json @checks.is_owner() - async def testcommand(self, context: SlashContext): + async def testcommand(self, interaction: ApplicationCommandInteraction): """ This is a testing command that does nothing. + Note: This is a SLASH command """ # Do your stuff here # Don't forget to remove "pass", that's just because there's no content in the method. pass + @commands.command( + name="testcommand", + description="This is a testing command that does nothing.", + ) + @checks.not_blacklisted() + @checks.is_owner() + async def testcommand(self, context: Context): + """ + This is a testing command that does nothing. + Note: This is a SLASH command + """ + pass + # And then we finally add the cog to the bot so that it can load, unload, reload and use it's content. def setup(bot): diff --git a/config.json b/config.json index 33fac8f8..823670f7 100644 --- a/config.json +++ b/config.json @@ -1,5 +1,7 @@ { + "prefix": "YOUR_BOT_PREFIX_HERE", "token": "YOUR_BOT_TOKEN_HERE", + "permissions": "YOUR_BOT_PERMISSIONS_HERE", "application_id": "YOUR_APPLICATION_ID_HERE", "owners": [ 123456789, diff --git a/exceptions/__init__.py b/exceptions/__init__.py index f2c30e92..efcb3920 100644 --- a/exceptions/__init__.py +++ b/exceptions/__init__.py @@ -1,3 +1,12 @@ +"""" +Copyright ยฉ Krypton 2021 - https://github.com/kkrypt0nn +Description: +This is a template to create your own discord bot in python. + +Version: 4.0 +""" + + class UserBlacklisted(Exception): def __init__(self, message="User is blacklisted!"): self.message = message diff --git a/helpers/checks.py b/helpers/checks.py index 2d3a4f73..d9f66590 100644 --- a/helpers/checks.py +++ b/helpers/checks.py @@ -1,6 +1,14 @@ +"""" +Copyright ยฉ Krypton 2021 - https://github.com/kkrypt0nn +Description: +This is a template to create your own discord bot in python. + +Version: 4.0 +""" + import json -from discord.ext import commands +from disnake.ext import commands from exceptions import * diff --git a/helpers/json_manager.py b/helpers/json_manager.py index c74bd4ff..0512ca2a 100644 --- a/helpers/json_manager.py +++ b/helpers/json_manager.py @@ -1,3 +1,11 @@ +"""" +Copyright ยฉ Krypton 2021 - https://github.com/kkrypt0nn +Description: +This is a template to create your own discord bot in python. + +Version: 4.0 +""" + import json diff --git a/requirements.txt b/requirements.txt index aeff09ad..84a25d0e 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,2 @@ aiohttp -discord-py-interactions -discord.py +disnake