diff --git a/.github/workflows/pylint.yml b/.github/workflows/pylint.yml new file mode 100644 index 0000000..668789a --- /dev/null +++ b/.github/workflows/pylint.yml @@ -0,0 +1,26 @@ +name: Pylint + +on: [push] + +jobs: + build: + runs-on: ubuntu-latest + strategy: + matrix: + python-version: ["3.10.6", "3.11.1"] + steps: + - uses: actions/checkout@v3 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v3 + with: + python-version: ${{ matrix.python-version }} + - name: Install pylint + run: | + python -m pip install --upgrade pip + pip install pylint + - name: Install dependencies + run: | + pip install -r requirements.txt + - name: Analysing the code with pylint + run: | + pylint $(git ls-files '*.py') diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..517217c --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +.idea +.vscode +cogs/__pycache__ +__pycache__ +.env +config.json \ No newline at end of file diff --git a/.pylintrc b/.pylintrc new file mode 100644 index 0000000..8318b6c --- /dev/null +++ b/.pylintrc @@ -0,0 +1,2 @@ +[MESSAGES CONTROL] +disable=missing-docstring,missing-module-docstring,line-too-long,no-member,global-statement,no-name-in-module \ No newline at end of file diff --git a/CONFIGURATION.md b/CONFIGURATION.md new file mode 100644 index 0000000..84c3a29 --- /dev/null +++ b/CONFIGURATION.md @@ -0,0 +1,32 @@ +# Configuration + +## File locations +If set to use a JSON file, the file must be in the root directory, if set to use environment variables, the environment variables must be set in the environment the bot is running in. + +## Token +Discord bot authentication token, can be generated in the [Developer Portal](https://discord.com/developers/applications/) + +| type | JSON file | environment | +|--------|-------------|---------------------| +| string | `Token` | `TOKEN` | + +## Owner ID +The owner ID of the bot, this is used for owner only commands. + +| type | JSON file | environment | +|--------|-------------|---------------------| +| string | `OwnerID` | `OWNERID` | + +## Sharded +Whether the bot is sharded or not, only enable this if your bot is in more then 1000 servers. + +| type | JSON file | environment | +|--------|-------------|---------------------| +| boolean | `Sharded` | `SHARDED` | + +## Branch +The branch of the bot, this is used for the `pull` command to pull from the correct branch + +| type | JSON file | environment | +|--------|-------------|---------------------| +| string | `Branch` | `BRANCH` | diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..8a47134 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,4 @@ +# Contributing +If you want to contribute, make a [fork](https://github.com/Soapy7261/DobbieBot/fork), make your changes there, and then make a [pull request](https://github.com/Soapy7261/DobbieBot/compare), it must also follow the [licence](https://github.com/Soapy7261/DobbieBot/blob/main/LICENCE) + +If you are contributing to fix a security issue, please see [SECURITY.md](./SECURITY.md) \ No newline at end of file diff --git a/LICENSE.txt b/LICENSE similarity index 97% rename from LICENSE.txt rename to LICENSE index d4b1854..78f7e6a 100644 --- a/LICENSE.txt +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2022 Soapy7261 +Copyright (c) 2024 Soapy7261 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index 06ce2ae..668004a 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,13 @@ # DobbieBot -Discord fork used: pycord +Discord fork used: py-cord Checkout [this to install it](https://docs.pycord.dev/en/master/installing.html). -There are some Id's what you need to change,
-this progam gets the bot tolken by using a .env file +# Self hosting + +## Creating a bot +2. Create a [Discord application](https://discord.com/developers/applications/). + You have to enable all intents. + +## Configuration +Please view the [config file](./CONFIGURATION.md) for more configuration options. \ No newline at end of file diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..aca0a40 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,23 @@ +# Security Policy + +## Supported Versions +Only the latest version of DobbieBot is supported, older versions are not supported. +| Version | Support status | +| ------- | ------------------ | +| 2.LATEST | ✅ Active | +| 1.X | ❌ EOL | + +## Valid Vulnerabilities +Vulnerabilities in this project mostly fall into one of the following categories: +- Default Permissions that give users access to something that should probably be private +- Injecting custom code into the bot +- Crashing the entire DobbieBot instance +- Overloading the instance and therefore making the bot unusable on other servers + +The following are explicitly not vulnerabilities inside DobbieBot: +- Poorly configured slash command permissions which allow users to execute privileged commands +- Issues otherwise specific to a server for example having a public log of deleted messages, moderations etc. + +## Reporting a Vulnerability +Please do not create a public issue about security vulnerabilities. To prevent abuse of the vulnerability +before a fix is available please create a private report here: https://github.com/Soapy7261/DobbieBot/security/advisories diff --git a/cogs/botinfo.py b/cogs/botinfo.py new file mode 100644 index 0000000..8e0edb3 --- /dev/null +++ b/cogs/botinfo.py @@ -0,0 +1,30 @@ +from discord import Embed, utils, Color +from discord.ext.commands import slash_command +from discord.ext import commands +class BotInfo(commands.Cog): + def __init__(self, bot): + self.bot = bot + + @commands.Cog.listener() + async def on_ready(self): + print('BotInfo cog loaded!') + + @slash_command(description='Get info about the bot') + async def botinfo(self, ctx): + embed = Embed( + title="DobbieBot", + description = "The Dobbie bot", + timestamp=utils.utcnow(), + color=Color.embed_background()) + embed.add_field(name="Ping:",value=round(self.bot.latency * 1000, 2) + "ms") + embed.add_field(name="Info about the bot", + value="""this bot is made by Soapy7261#7261 + and Dobbie#4778. To teach Dobbie how + Discord bots work and how py-cord works!""") + + embed.add_field(name="Main commands", value="/math\n/info") + embed.add_field(name="Github", value="https://github.com/Soapy7261/DobbieBot") + await ctx.respond(embed=embed) + +def setup(bot): + bot.add_cog(BotInfo(bot)) diff --git a/cogs/branch.py b/cogs/branch.py new file mode 100644 index 0000000..4ddc18f --- /dev/null +++ b/cogs/branch.py @@ -0,0 +1,21 @@ +import discord +from discord.ext import commands +from discord.ext.commands import slash_command +from utils import Utils +class Branch(commands.Cog): + def __init__(self, bot): + self.bot = bot + self.info = Utils.info() + + @commands.Cog.listener() + async def on_ready(self): + print('Branch cog loaded!') + + @slash_command(description='Only the owner of the bot can run this command', guild_ids=[955135608228024394]) + async def branch(self, ctx, branch: discord.Option(autocomplete=Utils.GetBranches, description='What branch to switch to', required=True)): + if ctx.interaction.user.id != int(self.info['OwnerID']): + return await ctx.respond("You don't have permission to use this command!", ephemeral=True) + await ctx.respond(f'You selected {branch}', ephemeral=True) + +def setup(bot): + bot.add_cog(Branch(bot)) diff --git a/cogs/cogs.py b/cogs/cogs.py new file mode 100644 index 0000000..7278220 --- /dev/null +++ b/cogs/cogs.py @@ -0,0 +1,43 @@ +import os +import discord +from discord.ext import commands +from discord.ext.commands import slash_command +from discord.errors import ExtensionAlreadyLoaded, ExtensionNotLoaded, ExtensionFailed +from utils import Utils +class Cogs(commands.Cog): + def __init__(self, bot): + self.bot = bot + self.info = Utils.info() + + @commands.Cog.listener() + async def on_ready(self): + print('Cogs cog loaded!') + + @slash_command(description='Load, unload, or reload cogs', guild_ids=[955135608228024394]) + async def cogs(self, ctx, action: discord.Option(choices=["Reload", "Load", "Unload"], description='What action to run', required=True), cog: discord.Option(autocomplete=Utils.get_cogs, description='The cog to run the action on', required=True)): + if ctx.author.id != int(self.info['OwnerID']): + return await ctx.respond("You don't have permission to use this command!", ephemeral=True) + if cog not in [f"{fn[:-3]}" for fn in os.listdir("commands")]: + await ctx.respond("That cog doesn't exist!", ephemeral=True) + return + await ctx.defer(ephemeral=True) + try: + if action == "Load": + self.bot.load_extension(f"commands.{cog}") + if action == "Unload": + self.bot.unload_extension(f"commands.{cog}") + if action == "Reload": + self.bot.reload_extension(f"commands.{cog}") + except ExtensionAlreadyLoaded: + await ctx.respond("Extension already loaded!", ephemeral=True) + return + except ExtensionNotLoaded: + await ctx.respond("Extension not loaded!", ephemeral=True) + return + except ExtensionFailed as error: + await ctx.respond(f"Extension failed to load!```py\n{str(error)}\n```", ephemeral=True) + return + await ctx.respond(f"{action}ed {cog}", ephemeral=True) + +def setup(bot): + bot.add_cog(Cogs(bot)) diff --git a/cogs/examples/cogexample.txt b/cogs/examples/cogexample.txt new file mode 100644 index 0000000..cfc3e1f --- /dev/null +++ b/cogs/examples/cogexample.txt @@ -0,0 +1,16 @@ +from discord import slash_command +from discord.ext import commands +class NAME(commands.Cog): + def __init__(self, bot): + self.bot = bot + + @commands.Cog.listener() + async def on_ready(self): + print('BLANK cog loaded!') + + @slash_command(description='Your description') + async def command(self, ctx): + await ctx.respond('Your response') + +def setup(bot): + bot.add_cog(NAME(bot)) \ No newline at end of file diff --git a/cogs/examples/defaultpermissions.txt b/cogs/examples/defaultpermissions.txt new file mode 100644 index 0000000..93cb934 --- /dev/null +++ b/cogs/examples/defaultpermissions.txt @@ -0,0 +1,16 @@ +from discord import slash_command, commands, default_permissions +class NAME(commands.Cog): + def __init__(self, bot): + self.bot = bot + + @commands.Cog.listener() + async def on_ready(self): + print('BLANK cog loaded!') + + @slash_command(description='Your description') + @default_permissions(administrator=True) # Tells discord to make the command admin only, so people without the permission can't see it + async def command(self, ctx): + await ctx.respond('Your response') + +def setup(bot): + bot.add_cog(NAME(bot)) \ No newline at end of file diff --git a/cogs/examples/defaultpermissionsgroup.txt b/cogs/examples/defaultpermissionsgroup.txt new file mode 100644 index 0000000..20c8ef0 --- /dev/null +++ b/cogs/examples/defaultpermissionsgroup.txt @@ -0,0 +1,17 @@ +from discord import slash_command, commands, discord +class NAME(commands.Cog): + def __init__(self, bot): + self.bot = bot + + @commands.Cog.listener() + async def on_ready(self): + print('BLANK cog loaded!') + + group = discord.SlashCommandGroup("group", "Group description", default_member_permissions=discord.Permissions(PERMISSIONIDHERE)) + + @group.command(description='Your description') + async def command(self, ctx): + await ctx.respond('Your response') + +def setup(bot): + bot.add_cog(NAME(bot)) \ No newline at end of file diff --git a/cogs/examples/deferexample.txt b/cogs/examples/deferexample.txt new file mode 100644 index 0000000..9753e71 --- /dev/null +++ b/cogs/examples/deferexample.txt @@ -0,0 +1,17 @@ +from discord import slash_command, commands +class NAME(commands.Cog): + def __init__(self, bot): + self.bot = bot + + @commands.Cog.listener() + async def on_ready(self): + print('BLANK cog loaded!') + + @slash_command(description='Your description') + async def command(self, ctx): + await ctx.defer() #This can also be ephemeral or invisible with parameters, this is mostly useful if what your doing takes a while so discord doesn't think your bot isn't responding + #Some code in here + await ctx.respond('Done!') + +def setup(bot): + bot.add_cog(NAME(bot)) \ No newline at end of file diff --git a/cogs/examples/slashcommandgroup.txt b/cogs/examples/slashcommandgroup.txt new file mode 100644 index 0000000..3b1029d --- /dev/null +++ b/cogs/examples/slashcommandgroup.txt @@ -0,0 +1,17 @@ +from discord import slash_command, commands +class NAME(commands.Cog): + def __init__(self, bot): + self.bot = bot + + @commands.Cog.listener() + async def on_ready(self): + print('BLANK cog loaded!') + + group = discord.SlashCommandGroup("group", "Group description") + + @group.command(description='Your description') + async def command(self, ctx): + await ctx.respond('Your response') + +def setup(bot): + bot.add_cog(NAME(bot)) \ No newline at end of file diff --git a/cogs/math.py b/cogs/math.py new file mode 100644 index 0000000..837efdd --- /dev/null +++ b/cogs/math.py @@ -0,0 +1,29 @@ +import discord +from discord.ext import commands +from discord.ext.commands import slash_command +class Math(commands.Cog): + def __init__(self, bot): + self.bot = bot + + @commands.Cog.listener() + async def on_ready(self): + print('Math cog loaded!') + + @slash_command(description="Run a calculation") + async def math(self, ctx, first: discord.Option(float, description="The first number"), second: discord.Option(float, description="The second number"), operation: discord.Option(description="What operation you want to run", choices=["+", "-", "*", "/"])): + if operation == '+': + oper = first + second + elif operation == '-': + oper = first - second + elif operation == '*': + oper = first * second + elif operation == '/': + if second == 0: + return await ctx.respond("You can't divide by 0!", ephemeral=True) + oper = first / second + embed=discord.Embed(title='Calculation', timestamp=discord.utils.utcnow(), color=discord.Color.green()) + embed.add_field(name='Your calculation is here!', value=f"{first}{operation}{second} = {oper}") + await ctx.respond(embed=embed) + +def setup(bot): + bot.add_cog(Math(bot)) diff --git a/cogs/reload.py b/cogs/reload.py new file mode 100644 index 0000000..31e07e3 --- /dev/null +++ b/cogs/reload.py @@ -0,0 +1,34 @@ +from asyncio import sleep as asyncsleep +import discord +from discord.ext.commands import slash_command +from discord.ext import commands +from utils import Utils +class Reload(commands.Cog): + def __init__(self, bot): + self.bot = bot + self.info = Utils.info() + + @commands.Cog.listener() + async def on_ready(self): + print('Reload cog loaded!') + + @slash_command(description='Only the owner of the bot can run this command', guild_ids=[955135608228024394]) + async def reload(self, ctx): + if ctx.author.id != int(self.info['OwnerID']): + return await ctx.respond("You don't have permission to use this command!", ephemeral=True) + await ctx.defer() + await self.bot.change_presence(activity=discord.Activity(type=discord.ActivityType.playing, name=f"Reloading commands, bot may be unresponsive | In {len(self.bot.guilds)} servers"), status=discord.Status.dnd) + await asyncsleep(1) + try: + await self.bot.sync_commands() + except Exception as error: + await ctx.respond ("Failed to reload commands!") + await ctx.respond ("```py\n" + str(error) + "\n```", ephemeral=True) + await asyncsleep(3) + return await self.bot.change_presence(activity=discord.Activity(type=discord.ActivityType.listening, name=f"my creator's keyboard | In {len(self.bot.guilds)} servers"), status=discord.Status.online) + await asyncsleep(3) + await self.bot.change_presence(activity=discord.Activity(type=discord.ActivityType.listening, name=f"my creator's keyboard | In {len(self.bot.guilds)} servers"), status=discord.Status.online) + return await ctx.respond("Finished!", ephemeral=True) + +def setup(bot): + bot.add_cog(Reload(bot)) diff --git a/cogs/restart.py b/cogs/restart.py new file mode 100644 index 0000000..b74084f --- /dev/null +++ b/cogs/restart.py @@ -0,0 +1,24 @@ +import discord +from discord.ext.commands import slash_command +from discord.ext import commands +from utils import Utils +class Restart(commands.Cog): + def __init__(self, bot): + self.bot = bot + self.info = Utils.info() + + @commands.Cog.listener() + async def on_ready(self): + print('Restart cog loaded!') + + @slash_command(description="Restart the bot", guild_ids=[955135608228024394]) + async def restart(self, ctx): + if ctx.author.id != int(self.info['OwnerID']): + return await ctx.respond("You don't have permission to use this command!", ephemeral=True) + await ctx.respond("Restarting.") + embed = discord.Embed(title="🔄 Restarting...", timestamp=discord.utils.utcnow(), color=discord.Color.orange()) + await self.bot.get_guild(955135608228024394).get_channel(1048306173071347782).send(embed=embed) + await self.bot.close() + +def setup(bot): + bot.add_cog(Restart(bot)) diff --git a/cogs/say.py b/cogs/say.py new file mode 100644 index 0000000..08fe466 --- /dev/null +++ b/cogs/say.py @@ -0,0 +1,20 @@ +from discord import Option, Embed, utils, Color +from discord.ext.commands import slash_command +from discord.ext import commands +class Say(commands.Cog): + def __init__(self, bot): + self.bot = bot + + @commands.Cog.listener() + async def on_ready(self): + print('Say cog loaded!') + + @slash_command(description="Say something through the bot") + async def say(self, ctx, message: Option(str, description="The message to say")): + await ctx.delete() + embed = Embed(title="Message from " + ctx.user.name, description=message, timestamp=utils.utcnow(), color=Color.embed_background()) + embed.timestamp = utils.utcnow() + await ctx.send(embed=embed) + +def setup(bot): + bot.add_cog(Say(bot)) diff --git a/example.config.json b/example.config.json new file mode 100644 index 0000000..7daad84 --- /dev/null +++ b/example.config.json @@ -0,0 +1,7 @@ +{ + "CONFIGURATION": "Please view configuration.md!", + "Token": "YourBotTokenHere", + "OwnerID": "YourIDHere", + "Sharded": false, + "Branch": "master" +} \ No newline at end of file diff --git a/example.env b/example.env new file mode 100644 index 0000000..2f484af --- /dev/null +++ b/example.env @@ -0,0 +1,4 @@ +TOKEN=YOURBOTTOKENHERE +OWNERID=OWNERIDHERE +SHARDED=FALSE +BRANCH=MASTER \ No newline at end of file diff --git a/launcher.py b/launcher.py index 635ea62..10ba4b3 100644 --- a/launcher.py +++ b/launcher.py @@ -1,14 +1,15 @@ -#This is for restarting the python script, before you make a pr to use os.exec() instead, please know that it doesn't run new code, it just restarts the existing script, so you'll have to restart the script manually after making changes -import subprocess, time +import subprocess +import time +subprocess.run("pip install -r requirements.txt", check=True) #Installs the requirements for the bot while True: print ("Starting bot...") - g = subprocess.run("git pull") # Pulls the latest code from GitHub, if you do not have git installed, you can remove this line + g = subprocess.run("git pull", check=True) #Pulls the latest code from GitHub if g.returncode != 0: - print ("Error pulling code from github, this is likely because you don't have git installed, if you do have git installed, please check your configuration for git and try again") - time.sleep(5) - pass - p = subprocess.run('py main.py') - if p.returncode != 0: - print ("Hmmm, something went wrong, restarting in 8 seconds...") + print ("""Error pulling code from github, this is + likely because you don't have git installed, + if you do have git installed, + please check your configuration for git + and try again""") + p = subprocess.run("py main.py", check=True) print('Restarting bot...') - time.sleep(4) #This is to prevent the script from restarting too fast, which causes discord to get rate limited \ No newline at end of file + time.sleep(4) diff --git a/main.py b/main.py index 716cf04..271cebb 100644 --- a/main.py +++ b/main.py @@ -1,169 +1,46 @@ -import discord -from discord.ext import commands -import os -from dotenv import load_dotenv - -load_dotenv() - - -intents = discord.Intents.default() -intents.message_content = True -bot = commands.Bot(debug_guilds=[955135608228024394], command_prefix="-", status=discord.Status.dnd, - activity=discord.Activity(type=discord.ActivityType.listening, name="keyboard noises and no errors"), - owner='820255805257023498', intents=intents, ) - -bot = discord.Bot() - +from discord import Bot, Intents, Status, Activity, ActivityType, Embed, Color, utils +from utils import Utils +info = Utils.info() +intents = Intents.all() +bot = Bot(debug_guilds=[955135608228024394], status=Status.dnd, activity=Activity(type=ActivityType.playing, name="Booting..."), intents=intents) +bot.load_extensions("cogs") +BOOTED = True @bot.listen() async def on_ready(): - embed = discord.Embed(title=":green_circle: Online!\nTime to mess around!", timestamp=discord.utils.utcnow(), - color=0x00ff00, ) - await bot.get_guild(955135608228024394).get_channel(1011649871511572500).send(embed=embed) - print("Now ready!") - - -@bot.slash_command(description="Restart the bot") -async def restart(ctx): - await ctx.respond("Restarting.") - embed = discord.Embed(title=":arrows_counterclockwise: Restarting...", timestamp=discord.utils.utcnow(), color=0xFFA500) - await bot.get_guild(955135608228024394).get_channel(1048306173071347782).send(embed=embed) - quit() - - -@bot.slash_command(name="cal1", description="run a calculation") -async def cal1(ctx, first: discord.Option(int), mark: discord.Option(description="What operation you want to run", choices=["+", "-", "*", "/"]), second: discord.Option(int)): - if mark == "+": - calcu = f"{first}+{second} = {first + second}" - print('cal done ') - if mark==('-'): - calcu=(f"{first}-{second} = {first - second}") - if mark==('*'): - calcu=(f"{first} {mark} {second} = {first * second}") - if mark== '/': - if first or second !=0: - calcu=(f"{first}/{second} = {first / second}") - embed=discord.Embed(title='calculation',timestamp=discord.utils.utcnow(),color=0x00ff00,) - embed.add_field(name='your calculation is here!', value=calcu) - await ctx.respond(embed=embed) - print(f'command cal runned; {calcu} {discord.user.User}') - - - - - - -@bot.slash_command(name='info', description='get info about the bot') -async def info(ctx): - embed = discord.Embed( - title="DobbieBot", - description ="The Dobbie bot ", - timestamp=discord.utils.utcnow(), - color=discord.Color.dark_gray()) - embed.add_field(name="ping",value=(f'ping = {round(bot.latency*1000, 2)}')) - embed.add_field(name="info about the bot", - value="this bot is made by Soapy7261#8558 and Dobbie#4778. To learn Dobbie how Discord bots work and how py-cord works!") - - embed.add_field(name="main commands", value="the /call1 comamnd and the /info command") - await ctx.respond(embed=embed) - - - - -@bot.slash_command(name="hello", description='say hello', guild=discord.Object(id=955135608228024394)) -async def hello(interaction: discord.Interaction): - await interaction.response.send_message(f"he {interaction.user}", ephemeral=True) - - - - - - - -@bot.slash_command(name="distance-thing", description="change the Mesure ting") - - -@bot.command() + global BOOTED + if not BOOTED: + print ("Reconnected(?)") + if BOOTED: + embed = Embed(title="🟢 Online!\nTime to mess around!", timestamp=utils.utcnow(), color=Color.green()) + await bot.get_guild(955135608228024394).get_channel(1011649871511572500).send(embed=embed) + await bot.change_presence(activity=Activity(type=ActivityType.listening, + name=f"my creator's keyboard | In {len(bot.guilds)} servers"), status=Status.online) + print(f"Ready! Logged in as {bot.user}") + BOOTED = False + +@bot.slash_command(description='Say hello', guild_ids=[955135608228024394]) +async def hello(ctx): + await ctx.respond(f"Hello {ctx.user.mention}!", ephemeral=True) + +@bot.slash_command(description='Test command') async def test(ctx): await ctx.send("te@st!") print("send command 'test!'") - -@bot.command() -async def add(ctx, add1: int, add2: int): - add.thing='this command is now merged in to the -call command use `-call', add1 , add2, ' and then whitout those stupid marks' - await ctx.send (add.thig) - print("command used 'add'.") - - -@bot.command() -async def multi(ctx, multi1: int, multi2: int): - await ctx.send(f"{multi1} * {multi2} = {multi1 * multi2}") - print("command used 'muti'.") - - -@bot.command() -async def divide(ctx, divide1: int, divide2: int): - if divide2 == 0: - await ctx.send("You fool. :smiling_imp: ") - return - await ctx.send(f"{divide1} / {divide2} = {divide1 / divide2}") - print("command used 'divide'.") - print(f"{divide1} / {divide2} = {divide1 / divide2}") - - -@bot.command() -async def sub(ctx, subt1: int, subt2: int): - await ctx.respond(f"{subt1}-{subt2} = {subt1 - subt2}") - print("command sub is used" + f"{subt1}-{subt2} = {subt1 - subt2}") - - -@bot.command() -async def papa(ctx, *, b1): - await ctx.send(b1) - -@bot.command() -async def cal(ctx,nr1: int, mark, nr2:int ): - - if mark==("+"): - calcu=(f"{nr1}+{nr2} = {nr1 + nr2}") - if mark==('-'): - calcu=(f"{nr1}-{nr2} = {nr1 - nr2}") - if mark==('*', 'x'): - if nr2!= 0: - calcu=(f"{nr1} {mark} {nr2} = {nr1 * nr2}") - if mark== '/': - if nr2 !=0: - calcu=(f"{nr1}/{nr2} = {nr1 / nr2}") - else: - calcu=("you fool!") - embed=discord.Embed(title='calculation',timestamp=discord.utils.utcnow(),color=0x00ff00,) - embed.add_field(name='your calculation is here!', value=calcu) - await ctx.send(embed=embed) - print(f'command cal runned; {calcu} {discord.user.User}') - - - - - - -@bot.event +@bot.listen() async def on_command_error(ctx, error): - if isinstance(error, discord.ext.commands.CommandError): - await ctx.reply(f"oh noo! there is an error:```py\n{str(error)}```message the owner for support") - embed = discord.Embed(title="Error :(", timestamp=discord.utils.utcnow(),color=0xff0000, ) - #embed.add_field(name = "Author:", value=message.author) - #embed.add_field(name = "Author ID:", value = message.author.id) - embed.add_field(name = "Error:", value=str(error)) - - await bot.get_guild(955135608228024394).get_channel(1017880577506017361).send(embed=embed) + await ctx.reply(f"An error occurred```py\n{str(error)}\n```Message the owner for support\nThis has been logged.") + embed = Embed(title="Error :(", timestamp=utils.utcnow(), color=Color.red()) + embed.add_field(name = "Error:", value=str(error)) + await bot.get_guild(955135608228024394).get_channel(1017880577506017361).send(embed=embed) @bot.listen() async def on_message(message): print ("message") - print (discord.message.content) + print (message.content) if "dobbie" in message.content.lower(): - print('your got fans') - await discord.PartialMessage.message.add_reaction() - -bot.run(os.getenv('TOKEN')) + print('you got fans') + #Add an eyes reaction + await message.add_reaction("👀") +bot.run(info['Token']) diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..275baf6 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,2 @@ +py-cord==2.4.0 +python-dotenv==0.21.1 \ No newline at end of file diff --git a/utils.py b/utils.py new file mode 100644 index 0000000..d10cc4c --- /dev/null +++ b/utils.py @@ -0,0 +1,72 @@ +from os import listdir, getenv +from json import load as jsonload +from json.decoder import JSONDecodeError +from sys import exit as sysexit +from aiohttp import ClientSession +try: + from dotenv import load_dotenv +except ImportError: + print("dotenv module not found! You will not be able to use a .env file.") +class Utils: + @staticmethod # This is a static method, which means you don't need to create an instance of the class to use it + def info() -> dict: + use_json = True # Change this to False if you want to use environment variables instead of a config.json file + response = {} + if use_json: + try: + with open("config.json", "r", encoding="UTF-8") as file: + response = jsonload(file) + except FileNotFoundError: + print("config.json file not found! Please create it.") + sysexit() + except JSONDecodeError: + print("config.json file is invalid! Please fix it.") + sysexit() + except EncodingWarning: + print("config.json file is not encoded in UTF-8! Please fix it.") + sysexit() + if not use_json: + load_dotenv() + response = { + "Token": getenv("TOKEN"), + "OwnerID": getenv("OWNERID") + } + return response + @staticmethod + def get_cogs(ctx) -> list: + info = Utils.info() + if ctx.interaction.user.id != int(info['OwnerID']): + return ["You don't have permission to use this command!"] + cogs = [] + for file in listdir('cogs'): + if ctx.interaction.data['options'][1]['value'] == "": + cogs.append(file) + continue + if file.startswith(ctx.interaction.data['options'][1]['value']): + cogs.append(file) + continue + if not cogs: + return ["No cogs found(!?)"] + return cogs + @staticmethod + async def get_branches(ctx) -> list: + info = Utils.info() + if ctx.interaction.user.id != int(info['OwnerID']): + return ["You don't have permission to use this command!"] + branches = [] + async with ClientSession() as session: + async with session.get('https://api.github.com/repos/Soapy7261/DobbieBot/branches') as resp: + if resp.status == 200: + data = await resp.json() + for branch in data: + if ctx.interaction.data['options'][0]['value'] == "": + branches.append(branch['name']) + continue + if branch['name'].startswith(ctx.interaction.data['options'][0]['value']): + branches.append(branch['name']) + continue + else: + branches.append("Error getting branches") + if not branches: + return ["No branches found(!?)"] + return branches