wiki


Documentation

Documentation

Environmental Setup

Getting Started:

Learn:

Install:


Creating a Python Virtual Environment:

  1. Navigate/create directory (folder) where the project is
    Navigate/create directory

  2. Create the python virtual environment
    Create venv

    The command python -m venv .venv is used:

    • -m runs a specific Python module
    • venv is the module for creating virtual environments
    • .venv is the name of the directory for the environment
  3. Activate python virtual environment
    Activate venv

    Inside the project directory (parent of .venv), run:

    . ./.venv/Scripts/activate
    
    • . is shorthand for source
    • ./ runs a script using a relative path
    • activate is the script that starts the environment
    • You’re in the virtual environment if you see (.venv) in your prompt
  4. Using Python and Pip in a virtual environment

    • Use .venv/bin/pip and .venv/bin/python to use the environment's versions
  5. Running the bot for the first time

    • Run the following commands inside the virtual environment:

      .venv/bin/pip install httpx
      .venv/bin/pip install discord
      .venv/bin/pip install pyyaml
      .venv/bin/pip install audioop-lts
      .venv/bin/pip install apscheduler
      
    • If you get a "module not found" error, try installing that module with pip.

  6. Deactivating the virtual environment
    Deactivate venv

    • Navigate to .venv/Scripts and run:

      deactivate
      
    • If (.venv) disappears from your prompt, it worked.

  7. Creating a server and bot account

Documentation

File Structure

This is what the project will look like at its parent folder level (top level).

  1. main.py:
  1. cogs/my_cog.py:
  1. utils/:
  1. utils/helpers.py:
  1. cache/:
  1. config/:


\

Documentation

Bot Token

Bot Token:

Documentation

GitIgnore Notes

.gitignore file

We will often want to add files to the repository directory just to make the bot run on our personal machines. We may not want to include these files in the actual repo as they are specific to testing. For instance, a config file that stores user information of the server that the bot is running on would be an example. We would not want user information of the test environment going on the main repository.

This is accomplished by adding these files to a file called .gitignore. Just add file or directory names to the file. If the file or directory you want to ignore is not in the main directory, add another .gitignore file in its directory.

Example:

Location of the .gitignore file

NOTE: Comments can and should be added for each entry explaining why or what the entry is for. Comments are denoted by the ‘#’ at the beginning of the line.

Example of gitignore in sub directory:

NOTE: The ‘*’ is a bash wildcard character that represents all entries in a directory. The ‘! .gitignore’ tells git to not ignore the .gitignore file; since we are ignoring all files in this directory.

Additional information for git ignore: gitignore documentation

Documentation

Bot Main File

Logging Level:

Intents:

Types of Intents:

Bot Token:

Documentation

Error Messages

Thus far, I have made error messages throughout the bot using the following pattern. These messages are sent to standard output(terminal) when the bot has an error.

Due to the structure of discord and the bot, exceptions and errors DO NOT crash the bot regardless if they are caught or not. With this in mind, we still want to catch all possible exceptions and errors and display error messages. This will make debugging easier and minimize unexpected outcomes of faulty code.\

Syntax:

Error: error message [function tag / identifiable name]

Example:

Error: config file could not be found [main::getToken]

Documentation

Making a New Feature

How to Get Started Developing New Features

Adding a New Cog

  1. Create a new Python file in the cogs/ directory, e.g. my_feature.py.
  2. Define a class that inherits from commands.Cog and decorate it accordingly.
    • For example:
from discord.ext import commands
class MyFeatureCog(commands.Cog):
def __init__(self, bot):
 		self.bot = bot
    
@commands.command()
    	async def my_command(self, ctx):
        		await ctx.send("Hello from my new feature!")
        
def setup(bot):
    	bot.add_cog(MyFeatureCog(bot))

  1. Import functions from utils/helpers.py in your cogs:
import utils.helpers as helpers
  1. Use functions in utils/helpers.py:
variable = helpers.function(arguments)
# or,
helpers.function(arguments)

Best Practices

  1. Keep Cogs Focused: Each cog should focus on a specific set of related commands or functionality to maintain clarity and organization.

  2. Use Helper Functions: Utilize helpers.py for any common functionality that may be used in multiple cogs.

  3. Documentation: Comment and document code in your cogs and helpers to make it easier for team members to understand the purpose and usage of code.

Documentation

Getting Data

Getting data from Discord:

You can get data regarding the discord server environment using parameters to the function when it is in a command decorator. [@commands.command()]

Parameters:

Documentation

Code Testing

Unit Testing

Unit testing is the practice of testing individual units or components of code to ensure they work as expected. A unit refers to the smallest testable part of an application, such as a function or a method. Unit tests typically focus on testing the logic within functions, ensuring that each part of the code behaves correctly.

In unit testing:

Benefits of Unit Testing

  1. Catches bugs early: Writing tests forces you to think about edge cases and logic. Bugs are easier to fix when caught early.
  2. Improves code quality: Writing tests often leads to better, more modular code as you design your code to be testable.
  3. Helps with refactoring: Unit tests provide confidence that your code works as expected when you make changes or refactor.
  4. Documentation: Tests can serve as documentation for how a function is expected to behave. {% endtab %}

{% tab title="Bot Examples" %}

How Unit Testing Helps with Developing Your Discord Bot

If you are developing a Discord bot, unit testing can be extremely helpful in ensuring that your bot behaves as expected. Here are a few ways unit testing can benefit you:

1. Testing Bot Commands

Discord bots often have commands that perform actions when a user types a command. Unit testing can check that the bot responds correctly under various conditions.

2. Testing Event Handlers

Your bot responds to events, such as when a new user joins the server or a message is sent. Unit tests can verify that the bot reacts correctly to specific events.

3. Testing External API Calls

Many bots interact with external APIs (e.g., fetching weather data or interacting with a database). Unit tests can mock external services to ensure that the bot handles API responses correctly.

4. Testing Database Interactions

If your bot interacts with a database (e.g., storing user preferences or storing logs), you can unit test database queries to ensure they work as expected.

\

Python Examples

1. Setup the Environment

First, make sure you have the necessary libraries installed:

Command: pip install pytest discord.py

\

2. Example: Testing a Simple Discord Command

Let’s say you have a simple Discord bot command that replies with a greeting when a user types !hello.

bot_commands.py

import discord
from discord.ext import commands
bot = commands.Bot(command\_prefix="!")
@bot.command(name="hello")
async def hello(ctx):
  await ctx.send(f"Hello, {ctx.author.name}!")

Now, you want to write a test to make sure the !hello command sends the correct greeting message.

3. Unit Test for the !hello Command

You’ll use unittest.mock to mock the ctx (the context that contains information about the message) and the send method to avoid sending actual messages on Discord.

test_bot_commands.py

import pytest
from unittest.mock import MagicMock
from bot_commands import bot, hello
@pytest.mark.asyncio
async def test\_hello\_command():
# Mock the context (ctx)
ctx = MagicMock()


# Mock the send method

ctx.send = MagicMock()

# Simulate a user with the name 'TestUser'

ctx.author.name = 'TestUser'

# Run the command

await hello(ctx)

# Check that the send method was called with the expected message

ctx.send.assert\_called\_with('Hello, TestUser!')

Explanation of the Test:

4. Example: Testing Event Handlers

Let’s say your bot sends a welcome message when a new member joins the server. You can test this event handler similarly.

bot_commands.py

@bot.event
async def on\_member\_join(member):
  channel = discord.utils.get(member.guild.text\_channels, name='general')
  if channel:
    await channel.send(f"Welcome to the server, {member.name}!")

Now, let's write a test to ensure the on_member_join event sends the correct welcome message.

test_bot_commands.py

from unittest.mock import MagicMock
import discord
from bot\_commands import on\_member\_join

@pytest.mark.asyncio
async def test\_on\_member\_join():
  # Mock the member object
  member = MagicMock()
  member.name = "NewUser"
  member.guild.text\_channels = \[MagicMock(name="general")]

  # Mock the send method
  member.guild.text\_channels\[0].send = MagicMock()
  
  # Call the event handler
  await on\_member\_join(member)

# Check that the send method was called with the expected message

member.guild.text\_channels\[0].send.assert\_called\_with("Welcome to the server, NewUser!")

Explanation:

5. Testing External API Calls (Mocking API Responses)

Many bots interact with external APIs (e.g., weather data). Let's mock an API call to show how you can test these interactions.

bot_commands.py

import requests
import discord
from discord.ext import commands

bot = commands.Bot(command\_prefix="!")
@bot.command(name="weather")
async def weather(ctx, location):
  # Simulate an API request to get weather data (mocked in the test)
  response = requests.get(f"https://api.weather.com/{location}")
  data = response.json()
  await ctx.send(f"The weather in {location} is {data\['temperature']}°C")

To test this, we can mock the requests.get method to avoid making real HTTP requests.

test_bot_commands.py


import pytest
from unittest.mock import patch, MagicMock
from bot\_commands import weather

@pytest.mark.asyncio
async def test\_weather\_command():

  # Mock the context
  ctx = MagicMock()
  ctx.send = MagicMock()
  
  # Mock the API response
  mock\_response = MagicMock()
  mock\_response.json.return\_value = {"temperature": 22}
  # Use patch to mock requests.get
  with patch("requests.get", return\_value=mock\_response):
    await weather(ctx, "London")


ctx.send.assert\_called\_with("The weather in London is 22°C")

Explanation:

Running the Tests

To run the tests, simply execute the following command: pytest test\_bot\_commands.py

Documentation

KeyCloak SSO R&D

Created main group for the Adventure Ted family. Then, created child groups for separate departments. This allowed easier role assignment through inheritance.










(This process outlines the steps to create a default role mapping for typical end user access)




 (Assigning the composite role just created allows basic access for all users in child groups of Adventure Ted)





Next order of business left here for direction for myself or Ron

Oauth2 compose.yaml example

nginx.conf example to proxy all subdomains to oauth2

keycloak configuration once the other two are set up…

Seems we may have to create a realm per department, or find some other solution within to have each dept go to their respective resources. will continue digging.

Ts stuff is proving to be quite a pain. Perhaps and overhaul to a different solution. If only I had friends :C (I'm so alone)

Git/GitHub Workflow

Prerequisite Knowledge