-
Notifications
You must be signed in to change notification settings - Fork 7
Development Guide
- Python 3.10>
- PostgreSQL
Go to your project terminal and type poetry install
, (BUT make sure you have poetry installed or else it won't work. although).
We have a configurations file named config.yml
(DO NOT TOUCH THIS, this will be our production configurations). Since all developers have their own instance of the bot, you have to create your own config file at the root folder of our project. with the explicit name of user-config.yml
and copy the configs inside config.yml
then change the configurations to suit your bot instance.
Example, inside your user-config.yml
file. (!ENV "token" means that it will get the key "token" from environment variables)
bot:
prefix: "pph-"
token: !ENV "token"
database:
database:
name: !ENV "db_name"
host: !ENV "db_host"
user: !ENV "db_user"
password: !ENV "db_pass"
api:
api_ninja: !ENV "api_ninja"
guild:
staff_roles: [1063415177980170300] # make sure to change these to match your local development server
dev_help_forum: 1083303587389648926
log_channel: 1064597414440341575
Our configurations are loaded by startup. If you change any of your local configurations, you'd have to restart the bot. We have a config.py
file where we load configurations into Python objects, for now it utilizes metaclasses (which is kind of overkill) but we can could change this to utilize pydantic-settings configuration loaders.
Note: Not all configurations are in config.yml
. Some are saved inside the database (mostly the configurations that can be modified while the bot is running). You can use the handler in bot/database/config_auto.py
to get/set configurations saved in the database.
Create a .env
file outside the bot folder. We have an .env.example file where you can check all the required environment variables.
│ .gitignore
│ config.yml
│ LICENSE.md
│ poetry.lock
│ pyproject.toml
│ README.md
│ .env # <<< here
└───bot
│ config.py
Go to Currency Data API and subscribe to the free tier to get your token.
Go to Discord Applications and create a new application. Next, under Settings on the left sidebar click Bot and look for Privileged Gateway Intents. Check PRESENCE INTENT, SERVER MEMBERS INTENT, and MESSAGE CONTENT INTENT
Under Settings, Click Bot and you'll see Reset Token
, Click that and accept the confirmation. Copy the token and paste it on your .env
Under Settings, Click OAuth2 and then URL Generator, Check Bot application.commands and Administrator. Scroll down and copy the invite link to invite the bot.
Make sure you have enabled Developer Mode on your discord account, you can see it at settings > advanced for you to be able to copy your development server's id, role's id, and so on to be put on user-config.yml guild values
We also have a migration library, yoyo.
It automatically migrates your files when you run the bot (poetry run python bot/main.py
)
Inside bot/cogs/
folder, we will put our Cogs in there.
We will store all discord UIs in bot/ui/
folder.
- views/ - All views in here
- modals/ - All modals in here
All database handlers are in bot/database/
The only things we should put inside main.py
are the things needed to setup the bot.
- Follow PEP8 standard styling.
- Always annotate your function parameters, and import the Class directly if ever ex:
from discord import Member, TextChannel, Interaction, ...
from discord.app_commands import command
@command()
async def test(self, interaction: Interaction, ...):
...
We will put our decorator utility functions in here. You can refer to this if you want to make your own decorator.
Contents:
A decorator for checking if the command invoker is a staff.
def is_staff():
"""
Example:
@is_staff()
@command(description='Bans a member')
@describe(member='the member to ban')
async def ban(interaction: discord.Interaction, member: discord.Member):
await interaction.response.send_message(f'Banned {member}')
"""
def predicate(interaction: Interaction) -> bool:
staff = False
for id_ in Moderation.staff_roles:
role = interaction.guild.get_role(id_)
if role in interaction.user.roles:
staff = True
break # Break the loop and continue the command if the invoker is a staff
return staff
return app_commands.check(predicate)