diff --git a/bot.py b/bot.py index d2d0909..368d1b1 100644 --- a/bot.py +++ b/bot.py @@ -66,7 +66,6 @@ If you want to use prefix commands, make sure to also enable the intent below in """ intents.message_content = True -# Setup both of the loggers class LoggingFormatter(logging.Formatter): @@ -103,17 +102,14 @@ class LoggingFormatter(logging.Formatter): logger = logging.getLogger("discord_bot") logger.setLevel(logging.INFO) -# Console handler console_handler = logging.StreamHandler() console_handler.setFormatter(LoggingFormatter()) -# File handler file_handler = logging.FileHandler(filename="discord.log", encoding="utf-8", mode="w") file_handler_formatter = logging.Formatter( "[{asctime}] [{levelname:<8}] {name}: {message}", "%Y-%m-%d %H:%M:%S", style="{" ) file_handler.setFormatter(file_handler_formatter) -# Add the handlers logger.addHandler(console_handler) logger.addHandler(file_handler) @@ -154,8 +150,25 @@ class DiscordBot(commands.Bot): """ The code in this function is executed whenever the bot will start. """ - for file in os.listdir(f"{os.path.realpath(os.path.dirname(__file__))}/cogs"): - if file.endswith(".py"): + cogs_path = f"{os.path.realpath(os.path.dirname(__file__))}/cogs" + + for folder in os.listdir(cogs_path): + folder_path = os.path.join(cogs_path, folder) + if os.path.isdir(folder_path) and not folder.startswith('__'): + for file in os.listdir(folder_path): + if file.endswith(".py") and not file.startswith('__'): + extension = file[:-3] + try: + await self.load_extension(f"cogs.{folder}.{extension}") + self.logger.info(f"Loaded extension '{folder}.{extension}'") + except Exception as e: + exception = f"{type(e).__name__}: {e}" + self.logger.error( + f"Failed to load extension {folder}.{extension}\n{exception}" + ) + + for file in os.listdir(cogs_path): + if file.endswith(".py") and not file.startswith('__'): extension = file[:-3] try: await self.load_extension(f"cogs.{extension}") diff --git a/cogs/fun/coinflip.py b/cogs/fun/coinflip.py new file mode 100644 index 0000000..a79e853 --- /dev/null +++ b/cogs/fun/coinflip.py @@ -0,0 +1,67 @@ +""" +Copyright © Krypton 2019-Present - https://github.com/kkrypt0nn (https://krypton.ninja) +Description: +🐍 A simple template to start to code your own and personalized Discord bot in Python + +Version: 6.4.0 +""" + +import random +import discord +from discord.ext import commands +from discord.ext.commands import Context + + +class Choice(discord.ui.View): + def __init__(self) -> None: + super().__init__() + self.value = None + + @discord.ui.button(label="Heads", style=discord.ButtonStyle.blurple) + async def confirm( + self, interaction: discord.Interaction, button: discord.ui.Button + ) -> None: + self.value = "heads" + self.stop() + + @discord.ui.button(label="Tails", style=discord.ButtonStyle.blurple) + async def cancel( + self, interaction: discord.Interaction, button: discord.ui.Button + ) -> None: + self.value = "tails" + self.stop() + + +class CoinFlip(commands.Cog, name="coinflip"): + def __init__(self, bot) -> None: + self.bot = bot + + @commands.hybrid_command( + name="coinflip", description="Make a coin flip, but give your bet before." + ) + async def coinflip(self, context: Context) -> None: + """ + Make a coin flip, but give your bet before. + + :param context: The hybrid command context. + """ + buttons = Choice() + embed = discord.Embed(description="What is your bet?", color=0xBEBEFE) + message = await context.send(embed=embed, view=buttons) + await buttons.wait() + result = random.choice(["heads", "tails"]) + if buttons.value == result: + embed = discord.Embed( + description=f"Correct! You guessed `{buttons.value}` and I flipped the coin to `{result}`.", + color=0xBEBEFE, + ) + else: + embed = discord.Embed( + description=f"Woops! You guessed `{buttons.value}` and I flipped the coin to `{result}`, better luck next time!", + color=0xE02B2B, + ) + await message.edit(embed=embed, view=None, content=None) + + +async def setup(bot) -> None: + await bot.add_cog(CoinFlip(bot)) diff --git a/cogs/fun/randomfact.py b/cogs/fun/randomfact.py new file mode 100644 index 0000000..6be4e14 --- /dev/null +++ b/cogs/fun/randomfact.py @@ -0,0 +1,43 @@ +""" +Copyright © Krypton 2019-Present - https://github.com/kkrypt0nn (https://krypton.ninja) +Description: +🐍 A simple template to start to code your own and personalized Discord bot in Python + +Version: 6.4.0 +""" + +import aiohttp +import discord +from discord.ext import commands +from discord.ext.commands import Context + + +class RandomFact(commands.Cog, name="randomfact"): + def __init__(self, bot) -> None: + self.bot = bot + + @commands.hybrid_command(name="randomfact", description="Get a random fact.") + async def randomfact(self, context: Context) -> None: + """ + Get a random fact. + + :param context: The hybrid command context. + """ + 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 = discord.Embed(description=data["text"], color=0xD75BF4) + else: + embed = discord.Embed( + title="Error!", + description="There is something wrong with the API, please try again later", + color=0xE02B2B, + ) + await context.send(embed=embed) + + +async def setup(bot) -> None: + await bot.add_cog(RandomFact(bot)) diff --git a/cogs/fun.py b/cogs/fun/rockpaperscissors.py similarity index 50% rename from cogs/fun.py rename to cogs/fun/rockpaperscissors.py index c65c32a..1dac786 100644 --- a/cogs/fun.py +++ b/cogs/fun/rockpaperscissors.py @@ -7,33 +7,11 @@ Version: 6.4.0 """ import random - -import aiohttp import discord from discord.ext import commands from discord.ext.commands import Context -class Choice(discord.ui.View): - def __init__(self) -> None: - super().__init__() - self.value = None - - @discord.ui.button(label="Heads", style=discord.ButtonStyle.blurple) - async def confirm( - self, interaction: discord.Interaction, button: discord.ui.Button - ) -> None: - self.value = "heads" - self.stop() - - @discord.ui.button(label="Tails", style=discord.ButtonStyle.blurple) - async def cancel( - self, interaction: discord.Interaction, button: discord.ui.Button - ) -> None: - self.value = "tails" - self.stop() - - class RockPaperScissors(discord.ui.Select): def __init__(self) -> None: options = [ @@ -93,59 +71,10 @@ class RockPaperScissorsView(discord.ui.View): self.add_item(RockPaperScissors()) -class Fun(commands.Cog, name="fun"): +class RPS(commands.Cog, name="rps"): def __init__(self, bot) -> None: self.bot = bot - @commands.hybrid_command(name="randomfact", description="Get a random fact.") - async def randomfact(self, context: Context) -> None: - """ - Get a random fact. - - :param context: The hybrid command context. - """ - # 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 = discord.Embed(description=data["text"], color=0xD75BF4) - else: - embed = discord.Embed( - title="Error!", - description="There is something wrong with the API, please try again later", - color=0xE02B2B, - ) - await context.send(embed=embed) - - @commands.hybrid_command( - name="coinflip", description="Make a coin flip, but give your bet before." - ) - async def coinflip(self, context: Context) -> None: - """ - Make a coin flip, but give your bet before. - - :param context: The hybrid command context. - """ - buttons = Choice() - embed = discord.Embed(description="What is your bet?", color=0xBEBEFE) - 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.value == result: - embed = discord.Embed( - description=f"Correct! You guessed `{buttons.value}` and I flipped the coin to `{result}`.", - color=0xBEBEFE, - ) - else: - embed = discord.Embed( - description=f"Woops! You guessed `{buttons.value}` and I flipped the coin to `{result}`, better luck next time!", - color=0xE02B2B, - ) - await message.edit(embed=embed, view=None, content=None) - @commands.hybrid_command( name="rps", description="Play the rock paper scissors game against the bot." ) @@ -160,4 +89,4 @@ class Fun(commands.Cog, name="fun"): async def setup(bot) -> None: - await bot.add_cog(Fun(bot)) + await bot.add_cog(RPS(bot)) diff --git a/cogs/general.py b/cogs/general.py deleted file mode 100644 index ec418b8..0000000 --- a/cogs/general.py +++ /dev/null @@ -1,327 +0,0 @@ -""" -Copyright © Krypton 2019-Present - https://github.com/kkrypt0nn (https://krypton.ninja) -Description: -🐍 A simple template to start to code your own and personalized Discord bot in Python - -Version: 6.4.0 -""" - -import platform -import random - -import aiohttp -import discord -from discord import app_commands -from discord.ext import commands -from discord.ext.commands import Context - - -class FeedbackForm(discord.ui.Modal, title="Feeedback"): - feedback = discord.ui.TextInput( - label="What do you think about this bot?", - style=discord.TextStyle.long, - placeholder="Type your answer here...", - required=True, - max_length=256, - ) - - async def on_submit(self, interaction: discord.Interaction): - self.interaction = interaction - self.answer = str(self.feedback) - self.stop() - - -class General(commands.Cog, name="general"): - def __init__(self, bot) -> None: - self.bot = bot - self.context_menu_user = app_commands.ContextMenu( - name="Grab ID", callback=self.grab_id - ) - self.bot.tree.add_command(self.context_menu_user) - self.context_menu_message = app_commands.ContextMenu( - name="Remove spoilers", callback=self.remove_spoilers - ) - self.bot.tree.add_command(self.context_menu_message) - - # Message context menu command - async def remove_spoilers( - self, interaction: discord.Interaction, message: discord.Message - ) -> None: - """ - Removes the spoilers from the message. This command requires the MESSAGE_CONTENT intent to work properly. - - :param interaction: The application command interaction. - :param message: The message that is being interacted with. - """ - spoiler_attachment = None - for attachment in message.attachments: - if attachment.is_spoiler(): - spoiler_attachment = attachment - break - embed = discord.Embed( - title="Message without spoilers", - description=message.content.replace("||", ""), - color=0xBEBEFE, - ) - if spoiler_attachment is not None: - embed.set_image(url=attachment.url) - await interaction.response.send_message(embed=embed, ephemeral=True) - - # User context menu command - async def grab_id( - self, interaction: discord.Interaction, user: discord.User - ) -> None: - """ - Grabs the ID of the user. - - :param interaction: The application command interaction. - :param user: The user that is being interacted with. - """ - embed = discord.Embed( - description=f"The ID of {user.mention} is `{user.id}`.", - color=0xBEBEFE, - ) - await interaction.response.send_message(embed=embed, ephemeral=True) - - @commands.hybrid_command( - name="help", description="List all commands the bot has loaded." - ) - async def help(self, context: Context) -> None: - embed = discord.Embed( - title="Help", description="List of available commands:", color=0xBEBEFE - ) - for i in self.bot.cogs: - if i == "owner" and not (await self.bot.is_owner(context.author)): - continue - cog = self.bot.get_cog(i.lower()) - commands = cog.get_commands() - data = [] - for command in commands: - description = command.description.partition("\n")[0] - data.append(f"{command.name} - {description}") - help_text = "\n".join(data) - embed.add_field( - name=i.capitalize(), value=f"```{help_text}```", inline=False - ) - await context.send(embed=embed) - - @commands.hybrid_command( - name="botinfo", - description="Get some useful (or not) information about the bot.", - ) - async def botinfo(self, context: Context) -> None: - """ - Get some useful (or not) information about the bot. - - :param context: The hybrid command context. - """ - embed = discord.Embed( - description="Used [Krypton's](https://krypton.ninja) template", - color=0xBEBEFE, - ) - embed.set_author(name="Bot Information") - embed.add_field(name="Owner:", 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) or {self.bot.bot_prefix} for normal commands", - inline=False, - ) - embed.set_footer(text=f"Requested by {context.author}") - await context.send(embed=embed) - - @commands.hybrid_command( - name="serverinfo", - description="Get some useful (or not) information about the server.", - ) - async def serverinfo(self, context: Context) -> None: - """ - Get some useful (or not) information about the server. - - :param context: The hybrid command context. - """ - roles = [role.name for role in context.guild.roles] - num_roles = len(roles) - if num_roles > 50: - roles = roles[:50] - roles.append(f">>>> Displaying [50/{num_roles}] Roles") - roles = ", ".join(roles) - - embed = discord.Embed( - title="**Server Name:**", description=f"{context.guild}", color=0xBEBEFE - ) - if context.guild.icon is not None: - embed.set_thumbnail(url=context.guild.icon.url) - embed.add_field(name="Server ID", value=context.guild.id) - embed.add_field(name="Member Count", value=context.guild.member_count) - embed.add_field( - name="Text/Voice Channels", value=f"{len(context.guild.channels)}" - ) - embed.add_field(name=f"Roles ({len(context.guild.roles)})", value=roles) - embed.set_footer(text=f"Created at: {context.guild.created_at}") - await context.send(embed=embed) - - @commands.hybrid_command( - name="ping", - description="Check if the bot is alive.", - ) - async def ping(self, context: Context) -> None: - """ - Check if the bot is alive. - - :param context: The hybrid command context. - """ - embed = discord.Embed( - title="🏓 Pong!", - description=f"The bot latency is {round(self.bot.latency * 1000)}ms.", - color=0xBEBEFE, - ) - await context.send(embed=embed) - - @commands.hybrid_command( - name="invite", - description="Get the invite link of the bot to be able to invite it.", - ) - async def invite(self, context: Context) -> None: - """ - Get the invite link of the bot to be able to invite it. - - :param context: The hybrid command context. - """ - embed = discord.Embed( - description=f"Invite me by clicking [here]({self.bot.invite_link}).", - color=0xD75BF4, - ) - try: - await context.author.send(embed=embed) - await context.send("I sent you a private message!") - except discord.Forbidden: - await context.send(embed=embed) - - @commands.hybrid_command( - name="server", - description="Get the invite link of the discord server of the bot for some support.", - ) - async def server(self, context: Context) -> None: - """ - Get the invite link of the discord server of the bot for some support. - - :param context: The hybrid command context. - """ - embed = discord.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: - await context.send(embed=embed) - - @commands.hybrid_command( - name="8ball", - description="Ask any question to the bot.", - ) - @app_commands.describe(question="The question you want to ask.") - async def eight_ball(self, context: Context, *, question: str) -> None: - """ - Ask any question to the bot. - - :param context: The hybrid command context. - :param question: The question that should be asked by the user. - """ - 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 = discord.Embed( - title="**My Answer:**", - description=f"{random.choice(answers)}", - color=0xBEBEFE, - ) - embed.set_footer(text=f"The question was: {question}") - await context.send(embed=embed) - - @commands.hybrid_command( - name="bitcoin", - description="Get the current price of bitcoin.", - ) - async def bitcoin(self, context: Context) -> None: - """ - Get the current price of bitcoin. - - :param context: The hybrid command context. - """ - # 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() - embed = discord.Embed( - title="Bitcoin price", - description=f"The current price is {data['bpi']['USD']['rate']} :dollar:", - color=0xBEBEFE, - ) - else: - embed = discord.Embed( - title="Error!", - description="There is something wrong with the API, please try again later", - color=0xE02B2B, - ) - await context.send(embed=embed) - - @app_commands.command( - name="feedback", description="Submit a feedback for the owners of the bot" - ) - async def feedback(self, interaction: discord.Interaction) -> None: - """ - Submit a feedback for the owners of the bot. - - :param context: The hybrid command context. - """ - feedback_form = FeedbackForm() - await interaction.response.send_modal(feedback_form) - - await feedback_form.wait() - interaction = feedback_form.interaction - await interaction.response.send_message( - embed=discord.Embed( - description="Thank you for your feedback, the owners have been notified about it.", - color=0xBEBEFE, - ) - ) - - app_owner = (await self.bot.application_info()).owner - await app_owner.send( - embed=discord.Embed( - title="New Feedback", - description=f"{interaction.user} (<@{interaction.user.id}>) has submitted a new feedback:\n```\n{feedback_form.answer}\n```", - color=0xBEBEFE, - ) - ) - - -async def setup(bot) -> None: - await bot.add_cog(General(bot)) diff --git a/cogs/general/bitcoin.py b/cogs/general/bitcoin.py new file mode 100644 index 0000000..0b8e75d --- /dev/null +++ b/cogs/general/bitcoin.py @@ -0,0 +1,50 @@ +""" +Copyright © Krypton 2019-Present - https://github.com/kkrypt0nn (https://krypton.ninja) +Description: +🐍 A simple template to start to code your own and personalized Discord bot in Python + +Version: 6.4.0 +""" + +import aiohttp +import discord +from discord.ext import commands +from discord.ext.commands import Context + + +class Bitcoin(commands.Cog, name="bitcoin"): + def __init__(self, bot) -> None: + self.bot = bot + + @commands.hybrid_command( + name="bitcoin", + description="Get the current price of bitcoin.", + ) + async def bitcoin(self, context: Context) -> None: + """ + Get the current price of bitcoin. + + :param context: The hybrid command context. + """ + 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() + embed = discord.Embed( + title="Bitcoin price", + description=f"The current price is {data['bpi']['USD']['rate']} :dollar:", + color=0xBEBEFE, + ) + else: + embed = discord.Embed( + title="Error!", + description="There is something wrong with the API, please try again later", + color=0xE02B2B, + ) + await context.send(embed=embed) + + +async def setup(bot) -> None: + await bot.add_cog(Bitcoin(bot)) diff --git a/cogs/general/botinfo.py b/cogs/general/botinfo.py new file mode 100644 index 0000000..6d81acb --- /dev/null +++ b/cogs/general/botinfo.py @@ -0,0 +1,48 @@ +""" +Copyright © Krypton 2019-Present - https://github.com/kkrypt0nn (https://krypton.ninja) +Description: +🐍 A simple template to start to code your own and personalized Discord bot in Python + +Version: 6.4.0 +""" + +import platform +import discord +from discord.ext import commands +from discord.ext.commands import Context + + +class BotInfo(commands.Cog, name="botinfo"): + def __init__(self, bot) -> None: + self.bot = bot + + @commands.hybrid_command( + name="botinfo", + description="Get some useful (or not) information about the bot.", + ) + async def botinfo(self, context: Context) -> None: + """ + Get some useful (or not) information about the bot. + + :param context: The hybrid command context. + """ + embed = discord.Embed( + description="Used [Krypton's](https://krypton.ninja) template", + color=0xBEBEFE, + ) + embed.set_author(name="Bot Information") + embed.add_field(name="Owner:", 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) or {self.bot.bot_prefix} for normal commands", + inline=False, + ) + embed.set_footer(text=f"Requested by {context.author}") + await context.send(embed=embed) + + +async def setup(bot) -> None: + await bot.add_cog(BotInfo(bot)) diff --git a/cogs/general/context_menus.py b/cogs/general/context_menus.py new file mode 100644 index 0000000..c9125d0 --- /dev/null +++ b/cogs/general/context_menus.py @@ -0,0 +1,66 @@ +""" +Copyright © Krypton 2019-Present - https://github.com/kkrypt0nn (https://krypton.ninja) +Description: +🐍 A simple template to start to code your own and personalized Discord bot in Python + +Version: 6.4.0 +""" + +import discord +from discord import app_commands +from discord.ext import commands + + +class ContextMenus(commands.Cog, name="context_menus"): + def __init__(self, bot) -> None: + self.bot = bot + self.context_menu_user = app_commands.ContextMenu( + name="Grab ID", callback=self.grab_id + ) + self.bot.tree.add_command(self.context_menu_user) + self.context_menu_message = app_commands.ContextMenu( + name="Remove spoilers", callback=self.remove_spoilers + ) + self.bot.tree.add_command(self.context_menu_message) + + async def remove_spoilers( + self, interaction: discord.Interaction, message: discord.Message + ) -> None: + """ + Removes the spoilers from the message. This command requires the MESSAGE_CONTENT intent to work properly. + + :param interaction: The application command interaction. + :param message: The message that is being interacted with. + """ + spoiler_attachment = None + for attachment in message.attachments: + if attachment.is_spoiler(): + spoiler_attachment = attachment + break + embed = discord.Embed( + title="Message without spoilers", + description=message.content.replace("||", ""), + color=0xBEBEFE, + ) + if spoiler_attachment is not None: + embed.set_image(url=attachment.url) + await interaction.response.send_message(embed=embed, ephemeral=True) + + async def grab_id( + self, interaction: discord.Interaction, user: discord.User + ) -> None: + """ + Grabs the ID of the user. + + :param interaction: The application command interaction. + :param user: The user that is being interacted with. + """ + embed = discord.Embed( + description=f"The ID of {user.mention} is `{user.id}`.", + color=0xBEBEFE, + ) + await interaction.response.send_message(embed=embed, ephemeral=True) + + +async def setup(bot) -> None: + await bot.add_cog(ContextMenus(bot)) diff --git a/cogs/general/eightball.py b/cogs/general/eightball.py new file mode 100644 index 0000000..5d9bc3c --- /dev/null +++ b/cogs/general/eightball.py @@ -0,0 +1,64 @@ +""" +Copyright © Krypton 2019-Present - https://github.com/kkrypt0nn (https://krypton.ninja) +Description: +🐍 A simple template to start to code your own and personalized Discord bot in Python + +Version: 6.4.0 +""" + +import random +import discord +from discord import app_commands +from discord.ext import commands +from discord.ext.commands import Context + + +class EightBall(commands.Cog, name="8ball"): + def __init__(self, bot) -> None: + self.bot = bot + + @commands.hybrid_command( + name="8ball", + description="Ask any question to the bot.", + ) + @app_commands.describe(question="The question you want to ask.") + async def eight_ball(self, context: Context, *, question: str) -> None: + """ + Ask any question to the bot. + + :param context: The hybrid command context. + :param question: The question that should be asked by the user. + """ + 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 = discord.Embed( + title="**My Answer:**", + description=f"{random.choice(answers)}", + color=0xBEBEFE, + ) + embed.set_footer(text=f"The question was: {question}") + await context.send(embed=embed) + + +async def setup(bot) -> None: + await bot.add_cog(EightBall(bot)) diff --git a/cogs/general/feedback.py b/cogs/general/feedback.py new file mode 100644 index 0000000..8535ee2 --- /dev/null +++ b/cogs/general/feedback.py @@ -0,0 +1,65 @@ +""" +Copyright © Krypton 2019-Present - https://github.com/kkrypt0nn (https://krypton.ninja) +Description: +🐍 A simple template to start to code your own and personalized Discord bot in Python + +Version: 6.4.0 +""" + +import discord +from discord import app_commands +from discord.ext import commands + + +class FeedbackForm(discord.ui.Modal, title="Feeedback"): + feedback = discord.ui.TextInput( + label="What do you think about this bot?", + style=discord.TextStyle.long, + placeholder="Type your answer here...", + required=True, + max_length=256, + ) + + async def on_submit(self, interaction: discord.Interaction): + self.interaction = interaction + self.answer = str(self.feedback) + self.stop() + + +class Feedback(commands.Cog, name="feedback"): + def __init__(self, bot) -> None: + self.bot = bot + + @app_commands.command( + name="feedback", description="Submit a feedback for the owners of the bot" + ) + async def feedback(self, interaction: discord.Interaction) -> None: + """ + Submit a feedback for the owners of the bot. + + :param interaction: The application command interaction. + """ + feedback_form = FeedbackForm() + await interaction.response.send_modal(feedback_form) + + await feedback_form.wait() + interaction = feedback_form.interaction + await interaction.response.send_message( + embed=discord.Embed( + description="Thank you for your feedback, the owners have been notified about it.", + color=0xBEBEFE, + ) + ) + + app_owner = (await self.bot.application_info()).owner + await app_owner.send( + embed=discord.Embed( + title="New Feedback", + description=f"{interaction.user} (<@{interaction.user.id}>) has submitted a new feedback:\n```\n{feedback_form.answer}\n```", + color=0xBEBEFE, + ) + ) + + +async def setup(bot) -> None: + await bot.add_cog(Feedback(bot)) diff --git a/cogs/general/help.py b/cogs/general/help.py new file mode 100644 index 0000000..6233400 --- /dev/null +++ b/cogs/general/help.py @@ -0,0 +1,94 @@ +""" +Copyright © Krypton 2019-Present - https://github.com/kkrypt0nn (https://krypton.ninja) +Description: +🐍 A simple template to start to code your own and personalized Discord bot in Python + +Version: 6.4.0 +""" + +import discord +from discord.ext import commands +from discord.ext.commands import Context + + +class Help(commands.Cog, name="help"): + def __init__(self, bot) -> None: + self.bot = bot + + @commands.hybrid_command( + name="help", description="List all commands the bot has loaded." + ) + async def help(self, context: Context) -> None: + embed = discord.Embed( + title="Help", description="List of available commands:", color=0xBEBEFE + ) + + category_mapping = { + "help": "General", + "botinfo": "General", + "serverinfo": "General", + "ping": "General", + "invite": "General", + "server": "General", + "8ball": "General", + "bitcoin": "General", + "feedback": "General", + "context_menus": "General", + + "randomfact": "Fun", + "coinflip": "Fun", + "rps": "Fun", + + "kick": "Moderation", + "ban": "Moderation", + "nick": "Moderation", + "purge": "Moderation", + "hackban": "Moderation", + "warnings": "Moderation", + "archive": "Moderation", + + + "sync": "Owner", + "cog_management": "Owner", + "shutdown": "Owner", + "say": "Owner", + + + "testcommand": "Template" + } + + + categories = {} + + for cog_name in self.bot.cogs: + cog = self.bot.get_cog(cog_name) + if cog: + commands_list = cog.get_commands() + for command in commands_list: + category = category_mapping.get(cog_name.lower(), "Other") + if category == "Owner" and not (await self.bot.is_owner(context.author)): + continue + + if category not in categories: + categories[category] = [] + + description = command.description.partition("\n")[0] if command.description else "No description available" + categories[category].append((command.name, description)) + + category_order = ["General", "Fun", "Moderation", "Template", "Owner", "Other"] + + for category in category_order: + if category in categories and categories[category]: + data = [] + for command_name, description in sorted(categories[category]): + data.append(f"{command_name} - {description}") + help_text = "\n".join(data) + embed.add_field( + name=category, value=f"```{help_text}```", inline=False + ) + + await context.send(embed=embed) + + +async def setup(bot) -> None: + await bot.add_cog(Help(bot)) diff --git a/cogs/general/invite.py b/cogs/general/invite.py new file mode 100644 index 0000000..a40ee15 --- /dev/null +++ b/cogs/general/invite.py @@ -0,0 +1,40 @@ +""" +Copyright © Krypton 2019-Present - https://github.com/kkrypt0nn (https://krypton.ninja) +Description: +🐍 A simple template to start to code your own and personalized Discord bot in Python + +Version: 6.4.0 +""" + +import discord +from discord.ext import commands +from discord.ext.commands import Context + + +class Invite(commands.Cog, name="invite"): + def __init__(self, bot) -> None: + self.bot = bot + + @commands.hybrid_command( + name="invite", + description="Get the invite link of the bot to be able to invite it.", + ) + async def invite(self, context: Context) -> None: + """ + Get the invite link of the bot to be able to invite it. + + :param context: The hybrid command context. + """ + embed = discord.Embed( + description=f"Invite me by clicking [here]({self.bot.invite_link}).", + color=0xD75BF4, + ) + try: + await context.author.send(embed=embed) + await context.send("I sent you a private message!") + except discord.Forbidden: + await context.send(embed=embed) + + +async def setup(bot) -> None: + await bot.add_cog(Invite(bot)) diff --git a/cogs/general/ping.py b/cogs/general/ping.py new file mode 100644 index 0000000..b012348 --- /dev/null +++ b/cogs/general/ping.py @@ -0,0 +1,37 @@ +""" +Copyright © Krypton 2019-Present - https://github.com/kkrypt0nn (https://krypton.ninja) +Description: +🐍 A simple template to start to code your own and personalized Discord bot in Python + +Version: 6.4.0 +""" + +import discord +from discord.ext import commands +from discord.ext.commands import Context + + +class Ping(commands.Cog, name="ping"): + def __init__(self, bot) -> None: + self.bot = bot + + @commands.hybrid_command( + name="ping", + description="Check if the bot is alive.", + ) + async def ping(self, context: Context) -> None: + """ + Check if the bot is alive. + + :param context: The hybrid command context. + """ + embed = discord.Embed( + title="🏓 Pong!", + description=f"The bot latency is {round(self.bot.latency * 1000)}ms.", + color=0xBEBEFE, + ) + await context.send(embed=embed) + + +async def setup(bot) -> None: + await bot.add_cog(Ping(bot)) diff --git a/cogs/general/server.py b/cogs/general/server.py new file mode 100644 index 0000000..9d40777 --- /dev/null +++ b/cogs/general/server.py @@ -0,0 +1,40 @@ +""" +Copyright © Krypton 2019-Present - https://github.com/kkrypt0nn (https://krypton.ninja) +Description: +🐍 A simple template to start to code your own and personalized Discord bot in Python + +Version: 6.4.0 +""" + +import discord +from discord.ext import commands +from discord.ext.commands import Context + + +class Server(commands.Cog, name="server"): + def __init__(self, bot) -> None: + self.bot = bot + + @commands.hybrid_command( + name="server", + description="Get the invite link of the discord server of the bot for some support.", + ) + async def server(self, context: Context) -> None: + """ + Get the invite link of the discord server of the bot for some support. + + :param context: The hybrid command context. + """ + embed = discord.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: + await context.send(embed=embed) + + +async def setup(bot) -> None: + await bot.add_cog(Server(bot)) diff --git a/cogs/general/serverinfo.py b/cogs/general/serverinfo.py new file mode 100644 index 0000000..c025f2b --- /dev/null +++ b/cogs/general/serverinfo.py @@ -0,0 +1,51 @@ +""" +Copyright © Krypton 2019-Present - https://github.com/kkrypt0nn (https://krypton.ninja) +Description: +🐍 A simple template to start to code your own and personalized Discord bot in Python + +Version: 6.4.0 +""" + +import discord +from discord.ext import commands +from discord.ext.commands import Context + + +class ServerInfo(commands.Cog, name="serverinfo"): + def __init__(self, bot) -> None: + self.bot = bot + + @commands.hybrid_command( + name="serverinfo", + description="Get some useful (or not) information about the server.", + ) + async def serverinfo(self, context: Context) -> None: + """ + Get some useful (or not) information about the server. + + :param context: The hybrid command context. + """ + roles = [role.name for role in context.guild.roles] + num_roles = len(roles) + if num_roles > 50: + roles = roles[:50] + roles.append(f">>>> Displaying [50/{num_roles}] Roles") + roles = ", ".join(roles) + + embed = discord.Embed( + title="**Server Name:**", description=f"{context.guild}", color=0xBEBEFE + ) + if context.guild.icon is not None: + embed.set_thumbnail(url=context.guild.icon.url) + embed.add_field(name="Server ID", value=context.guild.id) + embed.add_field(name="Member Count", value=context.guild.member_count) + embed.add_field( + name="Text/Voice Channels", value=f"{len(context.guild.channels)}" + ) + embed.add_field(name=f"Roles ({len(context.guild.roles)})", value=roles) + embed.set_footer(text=f"Created at: {context.guild.created_at}") + await context.send(embed=embed) + + +async def setup(bot) -> None: + await bot.add_cog(ServerInfo(bot)) diff --git a/cogs/moderation.py b/cogs/moderation.py deleted file mode 100644 index 510f4aa..0000000 --- a/cogs/moderation.py +++ /dev/null @@ -1,375 +0,0 @@ -""" -Copyright © Krypton 2019-Present - https://github.com/kkrypt0nn (https://krypton.ninja) -Description: -🐍 A simple template to start to code your own and personalized Discord bot in Python - -Version: 6.4.0 -""" - -import os -from datetime import datetime - -import discord -from discord import app_commands -from discord.ext import commands -from discord.ext.commands import Context - - -class Moderation(commands.Cog, name="moderation"): - def __init__(self, bot) -> None: - self.bot = bot - - @commands.hybrid_command( - name="kick", - description="Kick a user out of the server.", - ) - @commands.has_permissions(kick_members=True) - @commands.bot_has_permissions(kick_members=True) - @app_commands.describe( - user="The user that should be kicked.", - reason="The reason why the user should be kicked.", - ) - async def kick( - self, context: Context, user: discord.User, *, reason: str = "Not specified" - ) -> None: - """ - Kick a user out of the server. - - :param context: The hybrid command context. - :param user: The user that should be kicked from the server. - :param reason: The reason for the kick. Default is "Not specified". - """ - member = context.guild.get_member(user.id) or await context.guild.fetch_member( - user.id - ) - if member.guild_permissions.administrator: - embed = discord.Embed( - description="User has administrator permissions.", color=0xE02B2B - ) - await context.send(embed=embed) - else: - try: - embed = discord.Embed( - description=f"**{member}** was kicked by **{context.author}**!", - color=0xBEBEFE, - ) - embed.add_field(name="Reason:", value=reason) - await context.send(embed=embed) - try: - await member.send( - f"You were kicked by **{context.author}** from **{context.guild.name}**!\nReason: {reason}" - ) - except: - # Couldn't send a message in the private messages of the user - pass - await member.kick(reason=reason) - except: - embed = discord.Embed( - 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.send(embed=embed) - - @commands.hybrid_command( - name="nick", - description="Change the nickname of a user on a server.", - ) - @commands.has_permissions(manage_nicknames=True) - @commands.bot_has_permissions(manage_nicknames=True) - @app_commands.describe( - user="The user that should have a new nickname.", - nickname="The new nickname that should be set.", - ) - async def nick( - self, context: Context, user: discord.User, *, nickname: str = None - ) -> None: - """ - Change the nickname of a user on a server. - - :param context: The hybrid command context. - :param user: The user that should have its nickname changed. - :param nickname: The new nickname of the user. Default is None, which will reset the nickname. - """ - member = context.guild.get_member(user.id) or await context.guild.fetch_member( - user.id - ) - try: - await member.edit(nick=nickname) - embed = discord.Embed( - description=f"**{member}'s** new nickname is **{nickname}**!", - color=0xBEBEFE, - ) - await context.send(embed=embed) - except: - embed = discord.Embed( - 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.send(embed=embed) - - @commands.hybrid_command( - name="ban", - description="Bans a user from the server.", - ) - @commands.has_permissions(ban_members=True) - @commands.bot_has_permissions(ban_members=True) - @app_commands.describe( - user="The user that should be banned.", - reason="The reason why the user should be banned.", - ) - async def ban( - self, context: Context, user: discord.User, *, reason: str = "Not specified" - ) -> None: - """ - Bans a user from the server. - - :param context: The hybrid command context. - :param user: The user that should be banned from the server. - :param reason: The reason for the ban. Default is "Not specified". - """ - member = context.guild.get_member(user.id) or await context.guild.fetch_member( - user.id - ) - try: - if member.guild_permissions.administrator: - embed = discord.Embed( - description="User has administrator permissions.", color=0xE02B2B - ) - await context.send(embed=embed) - else: - embed = discord.Embed( - description=f"**{member}** was banned by **{context.author}**!", - color=0xBEBEFE, - ) - embed.add_field(name="Reason:", value=reason) - await context.send(embed=embed) - try: - await member.send( - f"You were banned by **{context.author}** from **{context.guild.name}**!\nReason: {reason}" - ) - except: - # Couldn't send a message in the private messages of the user - pass - await member.ban(reason=reason) - except: - embed = discord.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) - - @commands.hybrid_group( - name="warning", - description="Manage warnings of a user on a server.", - ) - @commands.has_permissions(manage_messages=True) - async def warning(self, context: Context) -> None: - """ - Manage warnings of a user on a server. - - :param context: The hybrid command context. - """ - if context.invoked_subcommand is None: - embed = discord.Embed( - description="Please specify a subcommand.\n\n**Subcommands:**\n`add` - Add a warning to a user.\n`remove` - Remove a warning from a user.\n`list` - List all warnings of a user.", - color=0xE02B2B, - ) - await context.send(embed=embed) - - @warning.command( - name="add", - description="Adds a warning to a user in the server.", - ) - @commands.has_permissions(manage_messages=True) - @app_commands.describe( - user="The user that should be warned.", - reason="The reason why the user should be warned.", - ) - async def warning_add( - self, context: Context, user: discord.User, *, reason: str = "Not specified" - ) -> None: - """ - Warns a user in his private messages. - - :param context: The hybrid command context. - :param user: The user that should be warned. - :param reason: The reason for the warn. Default is "Not specified". - """ - member = context.guild.get_member(user.id) or await context.guild.fetch_member( - user.id - ) - total = await self.bot.database.add_warn( - user.id, context.guild.id, context.author.id, reason - ) - embed = discord.Embed( - description=f"**{member}** was warned by **{context.author}**!\nTotal warns for this user: {total}", - color=0xBEBEFE, - ) - embed.add_field(name="Reason:", value=reason) - await context.send(embed=embed) - try: - await member.send( - f"You were warned by **{context.author}** in **{context.guild.name}**!\nReason: {reason}" - ) - except: - # 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}" - ) - - @warning.command( - name="remove", - description="Removes a warning from a user in the server.", - ) - @commands.has_permissions(manage_messages=True) - @app_commands.describe( - user="The user that should get their warning removed.", - warn_id="The ID of the warning that should be removed.", - ) - async def warning_remove( - self, context: Context, user: discord.User, warn_id: int - ) -> None: - """ - Warns a user in his private messages. - - :param context: The hybrid command context. - :param user: The user that should get their warning removed. - :param warn_id: The ID of the warning that should be removed. - """ - member = context.guild.get_member(user.id) or await context.guild.fetch_member( - user.id - ) - total = await self.bot.database.remove_warn(warn_id, user.id, context.guild.id) - embed = discord.Embed( - description=f"I've removed the warning **#{warn_id}** from **{member}**!\nTotal warns for this user: {total}", - color=0xBEBEFE, - ) - await context.send(embed=embed) - - @warning.command( - name="list", - description="Shows the warnings of a user in the server.", - ) - @commands.has_guild_permissions(manage_messages=True) - @app_commands.describe(user="The user you want to get the warnings of.") - async def warning_list(self, context: Context, user: discord.User) -> None: - """ - Shows the warnings of a user in the server. - - :param context: The hybrid command context. - :param user: The user you want to get the warnings of. - """ - warnings_list = await self.bot.database.get_warnings(user.id, context.guild.id) - embed = discord.Embed(title=f"Warnings of {user}", color=0xBEBEFE) - description = "" - if len(warnings_list) == 0: - description = "This user has no warnings." - else: - for warning in warnings_list: - description += f"• Warned by <@{warning[2]}>: **{warning[3]}** () - Warn ID #{warning[5]}\n" - embed.description = description - await context.send(embed=embed) - - @commands.hybrid_command( - name="purge", - description="Delete a number of messages.", - ) - @commands.has_guild_permissions(manage_messages=True) - @commands.bot_has_permissions(manage_messages=True) - @app_commands.describe(amount="The amount of messages that should be deleted.") - async def purge(self, context: Context, amount: int) -> None: - """ - Delete a number of messages. - - :param context: The hybrid command context. - :param amount: The number of messages that should be deleted. - """ - await context.send( - "Deleting messages..." - ) # Bit of a hacky way to make sure the bot responds to the interaction and doens't get a "Unknown Interaction" response - purged_messages = await context.channel.purge(limit=amount + 1) - embed = discord.Embed( - description=f"**{context.author}** cleared **{len(purged_messages)-1}** messages!", - color=0xBEBEFE, - ) - await context.channel.send(embed=embed) - - @commands.hybrid_command( - name="hackban", - description="Bans a user without the user having to be in the server.", - ) - @commands.has_permissions(ban_members=True) - @commands.bot_has_permissions(ban_members=True) - @app_commands.describe( - user_id="The user ID that should be banned.", - reason="The reason why the user should be banned.", - ) - async def hackban( - self, context: Context, user_id: str, *, reason: str = "Not specified" - ) -> None: - """ - Bans a user without the user having to be in the server. - - :param context: The hybrid command context. - :param user_id: The ID of the user that should be banned. - :param reason: The reason for the ban. Default is "Not specified". - """ - try: - await self.bot.http.ban(user_id, context.guild.id, reason=reason) - user = self.bot.get_user(int(user_id)) or await self.bot.fetch_user( - int(user_id) - ) - embed = discord.Embed( - description=f"**{user}** (ID: {user_id}) was banned by **{context.author}**!", - color=0xBEBEFE, - ) - embed.add_field(name="Reason:", value=reason) - await context.send(embed=embed) - except Exception: - embed = discord.Embed( - description="An error occurred while trying to ban the user. Make sure ID is an existing ID that belongs to a user.", - color=0xE02B2B, - ) - await context.send(embed=embed) - - @commands.hybrid_command( - name="archive", - description="Archives in a text file the last messages with a chosen limit of messages.", - ) - @commands.has_permissions(manage_messages=True) - @app_commands.describe( - limit="The limit of messages that should be archived.", - ) - async def archive(self, context: Context, limit: int = 10) -> None: - """ - Archives in a text file the last messages with a chosen limit of messages. This command requires the MESSAGE_CONTENT intent to work properly. - - :param limit: The limit of messages that should be archived. Default is 10. - """ - log_file = f"{context.channel.id}.log" - with open(log_file, "w", encoding="UTF-8") as f: - f.write( - f'Archived messages from: #{context.channel} ({context.channel.id}) in the guild "{context.guild}" ({context.guild.id}) at {datetime.now().strftime("%d.%m.%Y %H:%M:%S")}\n' - ) - async for message in context.channel.history( - limit=limit, before=context.message - ): - attachments = [] - for attachment in message.attachments: - attachments.append(attachment.url) - attachments_text = ( - f"[Attached File{'s' if len(attachments) >= 2 else ''}: {', '.join(attachments)}]" - if len(attachments) >= 1 - else "" - ) - f.write( - f"{message.created_at.strftime('%d.%m.%Y %H:%M:%S')} {message.author} {message.id}: {message.clean_content} {attachments_text}\n" - ) - f = discord.File(log_file) - await context.send(file=f) - os.remove(log_file) - - -async def setup(bot) -> None: - await bot.add_cog(Moderation(bot)) diff --git a/cogs/moderation/archive.py b/cogs/moderation/archive.py new file mode 100644 index 0000000..fea1323 --- /dev/null +++ b/cogs/moderation/archive.py @@ -0,0 +1,61 @@ +""" +Copyright © Krypton 2019-Present - https://github.com/kkrypt0nn (https://krypton.ninja) +Description: +🐍 A simple template to start to code your own and personalized Discord bot in Python + +Version: 6.4.0 +""" + +import os +from datetime import datetime +import discord +from discord import app_commands +from discord.ext import commands +from discord.ext.commands import Context + + +class Archive(commands.Cog, name="archive"): + def __init__(self, bot) -> None: + self.bot = bot + + @commands.hybrid_command( + name="archive", + description="Archives in a text file the last messages with a chosen limit of messages.", + ) + @commands.has_permissions(manage_messages=True) + @app_commands.describe( + limit="The limit of messages that should be archived.", + ) + async def archive(self, context: Context, limit: int = 10) -> None: + """ + Archives in a text file the last messages with a chosen limit of messages. This command requires the MESSAGE_CONTENT intent to work properly. + + :param context: The hybrid command context. + :param limit: The limit of messages that should be archived. Default is 10. + """ + log_file = f"{context.channel.id}.log" + with open(log_file, "w", encoding="UTF-8") as f: + f.write( + f'Archived messages from: #{context.channel} ({context.channel.id}) in the guild "{context.guild}" ({context.guild.id}) at {datetime.now().strftime("%d.%m.%Y %H:%M:%S")}\n' + ) + async for message in context.channel.history( + limit=limit, before=context.message + ): + attachments = [] + for attachment in message.attachments: + attachments.append(attachment.url) + attachments_text = ( + f"[Attached File{'s' if len(attachments) >= 2 else ''}: {', '.join(attachments)}]" + if len(attachments) >= 1 + else "" + ) + f.write( + f"{message.created_at.strftime('%d.%m.%Y %H:%M:%S')} {message.author} {message.id}: {message.clean_content} {attachments_text}\n" + ) + f = discord.File(log_file) + await context.send(file=f) + os.remove(log_file) + + +async def setup(bot) -> None: + await bot.add_cog(Archive(bot)) diff --git a/cogs/moderation/ban.py b/cogs/moderation/ban.py new file mode 100644 index 0000000..a2b859c --- /dev/null +++ b/cogs/moderation/ban.py @@ -0,0 +1,72 @@ +""" +Copyright © Krypton 2019-Present - https://github.com/kkrypt0nn (https://krypton.ninja) +Description: +🐍 A simple template to start to code your own and personalized Discord bot in Python + +Version: 6.4.0 +""" + +import discord +from discord import app_commands +from discord.ext import commands +from discord.ext.commands import Context + + +class Ban(commands.Cog, name="ban"): + def __init__(self, bot) -> None: + self.bot = bot + + @commands.hybrid_command( + name="ban", + description="Bans a user from the server.", + ) + @commands.has_permissions(ban_members=True) + @commands.bot_has_permissions(ban_members=True) + @app_commands.describe( + user="The user that should be banned.", + reason="The reason why the user should be banned.", + ) + async def ban( + self, context: Context, user: discord.User, *, reason: str = "Not specified" + ) -> None: + """ + Bans a user from the server. + + :param context: The hybrid command context. + :param user: The user that should be banned from the server. + :param reason: The reason for the ban. Default is "Not specified". + """ + member = context.guild.get_member(user.id) or await context.guild.fetch_member( + user.id + ) + try: + if member.guild_permissions.administrator: + embed = discord.Embed( + description="User has administrator permissions.", color=0xE02B2B + ) + await context.send(embed=embed) + else: + embed = discord.Embed( + description=f"**{member}** was banned by **{context.author}**!", + color=0xBEBEFE, + ) + embed.add_field(name="Reason:", value=reason) + await context.send(embed=embed) + try: + await member.send( + f"You were banned by **{context.author}** from **{context.guild.name}**!\nReason: {reason}" + ) + except: + pass + await member.ban(reason=reason) + except: + embed = discord.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) + + +async def setup(bot) -> None: + await bot.add_cog(Ban(bot)) diff --git a/cogs/moderation/hackban.py b/cogs/moderation/hackban.py new file mode 100644 index 0000000..581a1b3 --- /dev/null +++ b/cogs/moderation/hackban.py @@ -0,0 +1,59 @@ +""" +Copyright © Krypton 2019-Present - https://github.com/kkrypt0nn (https://krypton.ninja) +Description: +🐍 A simple template to start to code your own and personalized Discord bot in Python + +Version: 6.4.0 +""" + +import discord +from discord import app_commands +from discord.ext import commands +from discord.ext.commands import Context + + +class HackBan(commands.Cog, name="hackban"): + def __init__(self, bot) -> None: + self.bot = bot + + @commands.hybrid_command( + name="hackban", + description="Bans a user without the user having to be in the server.", + ) + @commands.has_permissions(ban_members=True) + @commands.bot_has_permissions(ban_members=True) + @app_commands.describe( + user_id="The user ID that should be banned.", + reason="The reason why the user should be banned.", + ) + async def hackban( + self, context: Context, user_id: str, *, reason: str = "Not specified" + ) -> None: + """ + Bans a user without the user having to be in the server. + + :param context: The hybrid command context. + :param user_id: The ID of the user that should be banned. + :param reason: The reason for the ban. Default is "Not specified". + """ + try: + await self.bot.http.ban(user_id, context.guild.id, reason=reason) + user = self.bot.get_user(int(user_id)) or await self.bot.fetch_user( + int(user_id) + ) + embed = discord.Embed( + description=f"**{user}** (ID: {user_id}) was banned by **{context.author}**!", + color=0xBEBEFE, + ) + embed.add_field(name="Reason:", value=reason) + await context.send(embed=embed) + except Exception: + embed = discord.Embed( + description="An error occurred while trying to ban the user. Make sure ID is an existing ID that belongs to a user.", + color=0xE02B2B, + ) + await context.send(embed=embed) + + +async def setup(bot) -> None: + await bot.add_cog(HackBan(bot)) diff --git a/cogs/moderation/kick.py b/cogs/moderation/kick.py new file mode 100644 index 0000000..3bc43b9 --- /dev/null +++ b/cogs/moderation/kick.py @@ -0,0 +1,71 @@ +""" +Copyright © Krypton 2019-Present - https://github.com/kkrypt0nn (https://krypton.ninja) +Description: +🐍 A simple template to start to code your own and personalized Discord bot in Python + +Version: 6.4.0 +""" + +import discord +from discord import app_commands +from discord.ext import commands +from discord.ext.commands import Context + + +class Kick(commands.Cog, name="kick"): + def __init__(self, bot) -> None: + self.bot = bot + + @commands.hybrid_command( + name="kick", + description="Kick a user out of the server.", + ) + @commands.has_permissions(kick_members=True) + @commands.bot_has_permissions(kick_members=True) + @app_commands.describe( + user="The user that should be kicked.", + reason="The reason why the user should be kicked.", + ) + async def kick( + self, context: Context, user: discord.User, *, reason: str = "Not specified" + ) -> None: + """ + Kick a user out of the server. + + :param context: The hybrid command context. + :param user: The user that should be kicked from the server. + :param reason: The reason for the kick. Default is "Not specified". + """ + member = context.guild.get_member(user.id) or await context.guild.fetch_member( + user.id + ) + if member.guild_permissions.administrator: + embed = discord.Embed( + description="User has administrator permissions.", color=0xE02B2B + ) + await context.send(embed=embed) + else: + try: + embed = discord.Embed( + description=f"**{member}** was kicked by **{context.author}**!", + color=0xBEBEFE, + ) + embed.add_field(name="Reason:", value=reason) + await context.send(embed=embed) + try: + await member.send( + f"You were kicked by **{context.author}** from **{context.guild.name}**!\nReason: {reason}" + ) + except: + pass + await member.kick(reason=reason) + except: + embed = discord.Embed( + 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.send(embed=embed) + + +async def setup(bot) -> None: + await bot.add_cog(Kick(bot)) diff --git a/cogs/moderation/nick.py b/cogs/moderation/nick.py new file mode 100644 index 0000000..04e637b --- /dev/null +++ b/cogs/moderation/nick.py @@ -0,0 +1,58 @@ +""" +Copyright © Krypton 2019-Present - https://github.com/kkrypt0nn (https://krypton.ninja) +Description: +🐍 A simple template to start to code your own and personalized Discord bot in Python + +Version: 6.4.0 +""" + +import discord +from discord import app_commands +from discord.ext import commands +from discord.ext.commands import Context + + +class Nick(commands.Cog, name="nick"): + def __init__(self, bot) -> None: + self.bot = bot + + @commands.hybrid_command( + name="nick", + description="Change the nickname of a user on a server.", + ) + @commands.has_permissions(manage_nicknames=True) + @commands.bot_has_permissions(manage_nicknames=True) + @app_commands.describe( + user="The user that should have a new nickname.", + nickname="The new nickname that should be set.", + ) + async def nick( + self, context: Context, user: discord.User, *, nickname: str = None + ) -> None: + """ + Change the nickname of a user on a server. + + :param context: The hybrid command context. + :param user: The user that should have its nickname changed. + :param nickname: The new nickname of the user. Default is None, which will reset the nickname. + """ + member = context.guild.get_member(user.id) or await context.guild.fetch_member( + user.id + ) + try: + await member.edit(nick=nickname) + embed = discord.Embed( + description=f"**{member}'s** new nickname is **{nickname}**!", + color=0xBEBEFE, + ) + await context.send(embed=embed) + except: + embed = discord.Embed( + 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.send(embed=embed) + + +async def setup(bot) -> None: + await bot.add_cog(Nick(bot)) diff --git a/cogs/moderation/purge.py b/cogs/moderation/purge.py new file mode 100644 index 0000000..bc17fe8 --- /dev/null +++ b/cogs/moderation/purge.py @@ -0,0 +1,43 @@ +""" +Copyright © Krypton 2019-Present - https://github.com/kkrypt0nn (https://krypton.ninja) +Description: +🐍 A simple template to start to code your own and personalized Discord bot in Python + +Version: 6.4.0 +""" + +import discord +from discord import app_commands +from discord.ext import commands +from discord.ext.commands import Context + + +class Purge(commands.Cog, name="purge"): + def __init__(self, bot) -> None: + self.bot = bot + + @commands.hybrid_command( + name="purge", + description="Delete a number of messages.", + ) + @commands.has_guild_permissions(manage_messages=True) + @commands.bot_has_permissions(manage_messages=True) + @app_commands.describe(amount="The amount of messages that should be deleted.") + async def purge(self, context: Context, amount: int) -> None: + """ + Delete a number of messages. + + :param context: The hybrid command context. + :param amount: The number of messages that should be deleted. + """ + await context.send("Deleting messages...") + purged_messages = await context.channel.purge(limit=amount + 1) + embed = discord.Embed( + description=f"**{context.author}** cleared **{len(purged_messages)-1}** messages!", + color=0xBEBEFE, + ) + await context.channel.send(embed=embed) + + +async def setup(bot) -> None: + await bot.add_cog(Purge(bot)) diff --git a/cogs/moderation/warnings.py b/cogs/moderation/warnings.py new file mode 100644 index 0000000..421d8e1 --- /dev/null +++ b/cogs/moderation/warnings.py @@ -0,0 +1,132 @@ +""" +Copyright © Krypton 2019-Present - https://github.com/kkrypt0nn (https://krypton.ninja) +Description: +🐍 A simple template to start to code your own and personalized Discord bot in Python + +Version: 6.4.0 +""" + +import discord +from discord import app_commands +from discord.ext import commands +from discord.ext.commands import Context + + +class Warnings(commands.Cog, name="warnings"): + def __init__(self, bot) -> None: + self.bot = bot + + @commands.hybrid_group( + name="warning", + description="Manage warnings of a user on a server.", + ) + @commands.has_permissions(manage_messages=True) + async def warning(self, context: Context) -> None: + """ + Manage warnings of a user on a server. + + :param context: The hybrid command context. + """ + if context.invoked_subcommand is None: + embed = discord.Embed( + description="Please specify a subcommand.\n\n**Subcommands:**\n`add` - Add a warning to a user.\n`remove` - Remove a warning from a user.\n`list` - List all warnings of a user.", + color=0xE02B2B, + ) + await context.send(embed=embed) + + @warning.command( + name="add", + description="Adds a warning to a user in the server.", + ) + @commands.has_permissions(manage_messages=True) + @app_commands.describe( + user="The user that should be warned.", + reason="The reason why the user should be warned.", + ) + async def warning_add( + self, context: Context, user: discord.User, *, reason: str = "Not specified" + ) -> None: + """ + Warns a user in his private messages. + + :param context: The hybrid command context. + :param user: The user that should be warned. + :param reason: The reason for the warn. Default is "Not specified". + """ + member = context.guild.get_member(user.id) or await context.guild.fetch_member( + user.id + ) + total = await self.bot.database.add_warn( + user.id, context.guild.id, context.author.id, reason + ) + embed = discord.Embed( + description=f"**{member}** was warned by **{context.author}**!\nTotal warns for this user: {total}", + color=0xBEBEFE, + ) + embed.add_field(name="Reason:", value=reason) + await context.send(embed=embed) + try: + await member.send( + f"You were warned by **{context.author}** in **{context.guild.name}**!\nReason: {reason}" + ) + except: + await context.send( + f"{member.mention}, you were warned by **{context.author}**!\nReason: {reason}" + ) + + @warning.command( + name="remove", + description="Removes a warning from a user in the server.", + ) + @commands.has_permissions(manage_messages=True) + @app_commands.describe( + user="The user that should get their warning removed.", + warn_id="The ID of the warning that should be removed.", + ) + async def warning_remove( + self, context: Context, user: discord.User, warn_id: int + ) -> None: + """ + Removes a warning from a user. + + :param context: The hybrid command context. + :param user: The user that should get their warning removed. + :param warn_id: The ID of the warning that should be removed. + """ + member = context.guild.get_member(user.id) or await context.guild.fetch_member( + user.id + ) + total = await self.bot.database.remove_warn(warn_id, user.id, context.guild.id) + embed = discord.Embed( + description=f"I've removed the warning **#{warn_id}** from **{member}**!\nTotal warns for this user: {total}", + color=0xBEBEFE, + ) + await context.send(embed=embed) + + @warning.command( + name="list", + description="Shows the warnings of a user in the server.", + ) + @commands.has_guild_permissions(manage_messages=True) + @app_commands.describe(user="The user you want to get the warnings of.") + async def warning_list(self, context: Context, user: discord.User) -> None: + """ + Shows the warnings of a user in the server. + + :param context: The hybrid command context. + :param user: The user you want to get the warnings of. + """ + warnings_list = await self.bot.database.get_warnings(user.id, context.guild.id) + embed = discord.Embed(title=f"Warnings of {user}", color=0xBEBEFE) + description = "" + if len(warnings_list) == 0: + description = "This user has no warnings." + else: + for warning in warnings_list: + description += f"• Warned by <@{warning[2]}>: **{warning[3]}** () - Warn ID #{warning[5]}\n" + embed.description = description + await context.send(embed=embed) + + +async def setup(bot) -> None: + await bot.add_cog(Warnings(bot)) diff --git a/cogs/owner.py b/cogs/owner.py deleted file mode 100644 index deaaa73..0000000 --- a/cogs/owner.py +++ /dev/null @@ -1,220 +0,0 @@ -""" -Copyright © Krypton 2019-Present - https://github.com/kkrypt0nn (https://krypton.ninja) -Description: -🐍 A simple template to start to code your own and personalized Discord bot in Python - -Version: 6.4.0 -""" - -import discord -from discord import app_commands -from discord.ext import commands -from discord.ext.commands import Context - - -class Owner(commands.Cog, name="owner"): - def __init__(self, bot) -> None: - self.bot = bot - - @commands.command( - name="sync", - description="Synchonizes the slash commands.", - ) - @app_commands.describe(scope="The scope of the sync. Can be `global` or `guild`") - @commands.is_owner() - async def sync(self, context: Context, scope: str) -> None: - """ - Synchonizes the slash commands. - - :param context: The command context. - :param scope: The scope of the sync. Can be `global` or `guild`. - """ - - if scope == "global": - await context.bot.tree.sync() - embed = discord.Embed( - description="Slash commands have been globally synchronized.", - color=0xBEBEFE, - ) - await context.send(embed=embed) - return - elif scope == "guild": - context.bot.tree.copy_global_to(guild=context.guild) - await context.bot.tree.sync(guild=context.guild) - embed = discord.Embed( - description="Slash commands have been synchronized in this guild.", - color=0xBEBEFE, - ) - await context.send(embed=embed) - return - embed = discord.Embed( - description="The scope must be `global` or `guild`.", color=0xE02B2B - ) - await context.send(embed=embed) - - @commands.command( - name="unsync", - description="Unsynchonizes the slash commands.", - ) - @app_commands.describe( - scope="The scope of the sync. Can be `global`, `current_guild` or `guild`" - ) - @commands.is_owner() - async def unsync(self, context: Context, scope: str) -> None: - """ - Unsynchonizes the slash commands. - - :param context: The command context. - :param scope: The scope of the sync. Can be `global`, `current_guild` or `guild`. - """ - - if scope == "global": - context.bot.tree.clear_commands(guild=None) - await context.bot.tree.sync() - embed = discord.Embed( - description="Slash commands have been globally unsynchronized.", - color=0xBEBEFE, - ) - await context.send(embed=embed) - return - elif scope == "guild": - context.bot.tree.clear_commands(guild=context.guild) - await context.bot.tree.sync(guild=context.guild) - embed = discord.Embed( - description="Slash commands have been unsynchronized in this guild.", - color=0xBEBEFE, - ) - await context.send(embed=embed) - return - embed = discord.Embed( - description="The scope must be `global` or `guild`.", color=0xE02B2B - ) - await context.send(embed=embed) - - @commands.hybrid_command( - name="load", - description="Load a cog", - ) - @app_commands.describe(cog="The name of the cog to load") - @commands.is_owner() - async def load(self, context: Context, cog: str) -> None: - """ - The bot will load the given cog. - - :param context: The hybrid command context. - :param cog: The name of the cog to load. - """ - try: - await self.bot.load_extension(f"cogs.{cog}") - except Exception: - embed = discord.Embed( - description=f"Could not load the `{cog}` cog.", color=0xE02B2B - ) - await context.send(embed=embed) - return - embed = discord.Embed( - description=f"Successfully loaded the `{cog}` cog.", color=0xBEBEFE - ) - await context.send(embed=embed) - - @commands.hybrid_command( - name="unload", - description="Unloads a cog.", - ) - @app_commands.describe(cog="The name of the cog to unload") - @commands.is_owner() - async def unload(self, context: Context, cog: str) -> None: - """ - The bot will unload the given cog. - - :param context: The hybrid command context. - :param cog: The name of the cog to unload. - """ - try: - await self.bot.unload_extension(f"cogs.{cog}") - except Exception: - embed = discord.Embed( - description=f"Could not unload the `{cog}` cog.", color=0xE02B2B - ) - await context.send(embed=embed) - return - embed = discord.Embed( - description=f"Successfully unloaded the `{cog}` cog.", color=0xBEBEFE - ) - await context.send(embed=embed) - - @commands.hybrid_command( - name="reload", - description="Reloads a cog.", - ) - @app_commands.describe(cog="The name of the cog to reload") - @commands.is_owner() - async def reload(self, context: Context, cog: str) -> None: - """ - The bot will reload the given cog. - - :param context: The hybrid command context. - :param cog: The name of the cog to reload. - """ - try: - await self.bot.reload_extension(f"cogs.{cog}") - except Exception: - embed = discord.Embed( - description=f"Could not reload the `{cog}` cog.", color=0xE02B2B - ) - await context.send(embed=embed) - return - embed = discord.Embed( - description=f"Successfully reloaded the `{cog}` cog.", color=0xBEBEFE - ) - await context.send(embed=embed) - - @commands.hybrid_command( - name="shutdown", - description="Make the bot shutdown.", - ) - @commands.is_owner() - async def shutdown(self, context: Context) -> None: - """ - Shuts down the bot. - - :param context: The hybrid command context. - """ - embed = discord.Embed(description="Shutting down. Bye! :wave:", color=0xBEBEFE) - await context.send(embed=embed) - await self.bot.close() - - @commands.hybrid_command( - name="say", - description="The bot will say anything you want.", - ) - @app_commands.describe(message="The message that should be repeated by the bot") - @commands.is_owner() - async def say(self, context: Context, *, message: str) -> None: - """ - The bot will say anything you want. - - :param context: The hybrid command context. - :param message: The message that should be repeated by the bot. - """ - await context.send(message) - - @commands.hybrid_command( - name="embed", - description="The bot will say anything you want, but within embeds.", - ) - @app_commands.describe(message="The message that should be repeated by the bot") - @commands.is_owner() - async def embed(self, context: Context, *, message: str) -> None: - """ - The bot will say anything you want, but using embeds. - - :param context: The hybrid command context. - :param message: The message that should be repeated by the bot. - """ - embed = discord.Embed(description=message, color=0xBEBEFE) - await context.send(embed=embed) - - -async def setup(bot) -> None: - await bot.add_cog(Owner(bot)) diff --git a/cogs/owner/cog_management.py b/cogs/owner/cog_management.py new file mode 100644 index 0000000..0832abe --- /dev/null +++ b/cogs/owner/cog_management.py @@ -0,0 +1,99 @@ +""" +Copyright © Krypton 2019-Present - https://github.com/kkrypt0nn (https://krypton.ninja) +Description: +🐍 A simple template to start to code your own and personalized Discord bot in Python + +Version: 6.4.0 +""" + +import discord +from discord import app_commands +from discord.ext import commands +from discord.ext.commands import Context + + +class CogManagement(commands.Cog, name="cog_management"): + def __init__(self, bot) -> None: + self.bot = bot + + @commands.hybrid_command( + name="load", + description="Load a cog", + ) + @app_commands.describe(cog="The name of the cog to load") + @commands.is_owner() + async def load(self, context: Context, cog: str) -> None: + """ + The bot will load the given cog. + + :param context: The hybrid command context. + :param cog: The name of the cog to load. + """ + try: + await self.bot.load_extension(f"cogs.{cog}") + except Exception: + embed = discord.Embed( + description=f"Could not load the `{cog}` cog.", color=0xE02B2B + ) + await context.send(embed=embed) + return + embed = discord.Embed( + description=f"Successfully loaded the `{cog}` cog.", color=0xBEBEFE + ) + await context.send(embed=embed) + + @commands.hybrid_command( + name="unload", + description="Unloads a cog.", + ) + @app_commands.describe(cog="The name of the cog to unload") + @commands.is_owner() + async def unload(self, context: Context, cog: str) -> None: + """ + The bot will unload the given cog. + + :param context: The hybrid command context. + :param cog: The name of the cog to unload. + """ + try: + await self.bot.unload_extension(f"cogs.{cog}") + except Exception: + embed = discord.Embed( + description=f"Could not unload the `{cog}` cog.", color=0xE02B2B + ) + await context.send(embed=embed) + return + embed = discord.Embed( + description=f"Successfully unloaded the `{cog}` cog.", color=0xBEBEFE + ) + await context.send(embed=embed) + + @commands.hybrid_command( + name="reload", + description="Reloads a cog.", + ) + @app_commands.describe(cog="The name of the cog to reload") + @commands.is_owner() + async def reload(self, context: Context, cog: str) -> None: + """ + The bot will reload the given cog. + + :param context: The hybrid command context. + :param cog: The name of the cog to reload. + """ + try: + await self.bot.reload_extension(f"cogs.{cog}") + except Exception: + embed = discord.Embed( + description=f"Could not reload the `{cog}` cog.", color=0xE02B2B + ) + await context.send(embed=embed) + return + embed = discord.Embed( + description=f"Successfully reloaded the `{cog}` cog.", color=0xBEBEFE + ) + await context.send(embed=embed) + + +async def setup(bot) -> None: + await bot.add_cog(CogManagement(bot)) diff --git a/cogs/owner/say.py b/cogs/owner/say.py new file mode 100644 index 0000000..6965400 --- /dev/null +++ b/cogs/owner/say.py @@ -0,0 +1,52 @@ +""" +Copyright © Krypton 2019-Present - https://github.com/kkrypt0nn (https://krypton.ninja) +Description: +🐍 A simple template to start to code your own and personalized Discord bot in Python + +Version: 6.4.0 +""" + +import discord +from discord import app_commands +from discord.ext import commands +from discord.ext.commands import Context + + +class Say(commands.Cog, name="say"): + def __init__(self, bot) -> None: + self.bot = bot + + @commands.hybrid_command( + name="say", + description="The bot will say anything you want.", + ) + @app_commands.describe(message="The message that should be repeated by the bot") + @commands.is_owner() + async def say(self, context: Context, *, message: str) -> None: + """ + The bot will say anything you want. + + :param context: The hybrid command context. + :param message: The message that should be repeated by the bot. + """ + await context.send(message) + + @commands.hybrid_command( + name="embed", + description="The bot will say anything you want, but within embeds.", + ) + @app_commands.describe(message="The message that should be repeated by the bot") + @commands.is_owner() + async def embed(self, context: Context, *, message: str) -> None: + """ + The bot will say anything you want, but using embeds. + + :param context: The hybrid command context. + :param message: The message that should be repeated by the bot. + """ + embed = discord.Embed(description=message, color=0xBEBEFE) + await context.send(embed=embed) + + +async def setup(bot) -> None: + await bot.add_cog(Say(bot)) diff --git a/cogs/owner/shutdown.py b/cogs/owner/shutdown.py new file mode 100644 index 0000000..28352f4 --- /dev/null +++ b/cogs/owner/shutdown.py @@ -0,0 +1,35 @@ +""" +Copyright © Krypton 2019-Present - https://github.com/kkrypt0nn (https://krypton.ninja) +Description: +🐍 A simple template to start to code your own and personalized Discord bot in Python + +Version: 6.4.0 +""" + +import discord +from discord.ext import commands +from discord.ext.commands import Context + + +class Shutdown(commands.Cog, name="shutdown"): + def __init__(self, bot) -> None: + self.bot = bot + + @commands.hybrid_command( + name="shutdown", + description="Make the bot shutdown.", + ) + @commands.is_owner() + async def shutdown(self, context: Context) -> None: + """ + Shuts down the bot. + + :param context: The hybrid command context. + """ + embed = discord.Embed(description="Shutting down. Bye! :wave:", color=0xBEBEFE) + await context.send(embed=embed) + await self.bot.close() + + +async def setup(bot) -> None: + await bot.add_cog(Shutdown(bot)) diff --git a/cogs/owner/sync.py b/cogs/owner/sync.py new file mode 100644 index 0000000..89395e1 --- /dev/null +++ b/cogs/owner/sync.py @@ -0,0 +1,94 @@ +""" +Copyright © Krypton 2019-Present - https://github.com/kkrypt0nn (https://krypton.ninja) +Description: +🐍 A simple template to start to code your own and personalized Discord bot in Python + +Version: 6.4.0 +""" + +import discord +from discord import app_commands +from discord.ext import commands +from discord.ext.commands import Context + + +class Sync(commands.Cog, name="sync"): + def __init__(self, bot) -> None: + self.bot = bot + + @commands.command( + name="sync", + description="Synchonizes the slash commands.", + ) + @app_commands.describe(scope="The scope of the sync. Can be `global` or `guild`") + @commands.is_owner() + async def sync(self, context: Context, scope: str) -> None: + """ + Synchonizes the slash commands. + + :param context: The command context. + :param scope: The scope of the sync. Can be `global` or `guild`. + """ + if scope == "global": + await context.bot.tree.sync() + embed = discord.Embed( + description="Slash commands have been globally synchronized.", + color=0xBEBEFE, + ) + await context.send(embed=embed) + return + elif scope == "guild": + context.bot.tree.copy_global_to(guild=context.guild) + await context.bot.tree.sync(guild=context.guild) + embed = discord.Embed( + description="Slash commands have been synchronized in this guild.", + color=0xBEBEFE, + ) + await context.send(embed=embed) + return + embed = discord.Embed( + description="The scope must be `global` or `guild`.", color=0xE02B2B + ) + await context.send(embed=embed) + + @commands.command( + name="unsync", + description="Unsynchonizes the slash commands.", + ) + @app_commands.describe( + scope="The scope of the sync. Can be `global`, `current_guild` or `guild`" + ) + @commands.is_owner() + async def unsync(self, context: Context, scope: str) -> None: + """ + Unsynchonizes the slash commands. + + :param context: The command context. + :param scope: The scope of the sync. Can be `global`, `current_guild` or `guild`. + """ + if scope == "global": + context.bot.tree.clear_commands(guild=None) + await context.bot.tree.sync() + embed = discord.Embed( + description="Slash commands have been globally unsynchronized.", + color=0xBEBEFE, + ) + await context.send(embed=embed) + return + elif scope == "guild": + context.bot.tree.clear_commands(guild=context.guild) + await context.bot.tree.sync(guild=context.guild) + embed = discord.Embed( + description="Slash commands have been unsynchronized in this guild.", + color=0xBEBEFE, + ) + await context.send(embed=embed) + return + embed = discord.Embed( + description="The scope must be `global` or `guild`.", color=0xE02B2B + ) + await context.send(embed=embed) + + +async def setup(bot) -> None: + await bot.add_cog(Sync(bot)) diff --git a/cogs/template.py b/cogs/template/testcommand.py similarity index 60% rename from cogs/template.py rename to cogs/template/testcommand.py index a383764..947da85 100644 --- a/cogs/template.py +++ b/cogs/template/testcommand.py @@ -10,13 +10,10 @@ from discord.ext import commands from discord.ext.commands import Context -# Here we name the cog and create a new class for the cog. -class Template(commands.Cog, name="template"): +class TestCommand(commands.Cog, name="testcommand"): def __init__(self, bot) -> None: self.bot = bot - # Here you can just add your own commands, you'll always need to provide "self" as first parameter. - @commands.hybrid_command( name="testcommand", description="This is a testing command that does nothing.", @@ -27,12 +24,8 @@ class Template(commands.Cog, name="template"): :param context: The application command context. """ - # Do your stuff here - - # Don't forget to remove "pass", I added this just because there's no content in the method. pass -# And then we finally add the cog to the bot so that it can load, unload, reload and use it's content. async def setup(bot) -> None: - await bot.add_cog(Template(bot)) + await bot.add_cog(TestCommand(bot))