Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 46 additions & 7 deletions techsupport_bot/bot.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,13 @@ class TechSupportBot(commands.Bot):
the bot needs to request from discord
allowed_mentions (discord.AllowedMentions): What the bot is, or is not,
allowed to mention

Attrs:
CONFIG_PATH (str): The hard coded path to the yaml config file
EXTENSIONS_DIR_NAME (str): The hardcoded folder for commands
EXTENSIONS_DIR (str): The list of all files in the EXTENSIONS_DIR_NAME folder
FUNCTIONS_DIR_NAME (str):The hardcoded folder for functions
FUNCTIONS_DIR (str):The list of all files in the FUNCTIONS_DIR_NAME folder
"""

CONFIG_PATH: str = "./config.yml"
Expand Down Expand Up @@ -284,6 +291,9 @@ async def create_new_context_config(self: Self, guild_id: str) -> munch.Munch:

Args:
guild_id (str): The guild ID the config will be for. Only used for storing the config

Returns:
munch.Munch: The new config object ready to use
"""
extensions_config = munch.DefaultMunch(None)

Expand Down Expand Up @@ -385,6 +395,10 @@ async def get_log_channel_from_guild(
Args:
guild (discord.Guild): the guild object to reference
key (str): the key to use when looking up the channel

Returns:
str | None: If the log channel exists, this will be the string of the ID
Otherwise it will be None
"""
if not guild:
return None
Expand Down Expand Up @@ -562,9 +576,12 @@ async def on_command_error(

# Postgres setup function

async def get_postgres_ref(self: Self) -> None:
async def get_postgres_ref(self: Self) -> gino.GinoEngine:
"""Connects to postgres based on the database login defined the in the file_config
Adds self.db to be the database reference

Returns:
gino.GinoEngine: The database connection as a gino object
"""
await self.logger.send_log(
message="Obtaining and binding to Gino instance",
Expand Down Expand Up @@ -602,7 +619,13 @@ async def get_postgres_ref(self: Self) -> None:

async def get_potential_extensions(self: Self) -> list[str]:
"""Gets the current list of extensions in the defined directory.
This ONLY gets commands, not functions"""
This ONLY gets commands, not functions

Returns:
list[str]: Gets a list of the string names of every python file
in the commands folder
"""

self.logger.console.info(f"Searching {self.EXTENSIONS_DIR} for extensions")
extensions_list = [
os.path.basename(f)[:-3]
Expand All @@ -613,7 +636,12 @@ async def get_potential_extensions(self: Self) -> list[str]:

async def get_potential_function_extensions(self: Self) -> list[str]:
"""Gets the current list of extensions in the defined directory.
This ONLY gets functions, not commands"""
This ONLY gets functions, not commands

Returns:
list[str]: Gets a list of the string names of every python file
in the functions folder
"""
self.logger.console.info(f"Searching {self.FUNCTIONS_DIR} for extensions")
extensions_list = [
os.path.basename(f)[:-3]
Expand Down Expand Up @@ -678,6 +706,9 @@ def get_command_extension_name(self: Self, command: commands.Command) -> str:

Args:
command (commands.Command): the command to reference

Returns:
str: The name of the extension name that houses a prefix command.
"""
if not command.module.startswith(f"{self.EXTENSIONS_DIR_NAME}."):
return None
Expand Down Expand Up @@ -713,13 +744,14 @@ async def register_file_extension(

async def is_bot_admin(self: Self, member: discord.Member) -> bool:
"""Processes command context against admin/owner data.

Command checks are disabled if the context author is the owner.

They are also ignored if the author is bot admin in the config.

Args:
member (discord.Member): the context associated with the command

Returns:
bool: True if the member is a bot admin. False if it isn't
"""
await self.logger.send_log(
message="Checking context against bot admins",
Expand All @@ -746,7 +778,11 @@ async def is_bot_admin(self: Self, member: discord.Member) -> bool:
return False

async def get_owner(self: Self) -> discord.User | None:
"""Gets the owner object from the bot application."""
"""Gets the owner object from the bot application.

Returns:
discord.User | None: The User object of the owner of the application on discords side
"""
if not self.owner:
try:
# If this isn't console only, it is a forever recursion
Expand All @@ -764,10 +800,13 @@ async def get_owner(self: Self) -> discord.User | None:

async def get_prefix(self: Self, message: discord.Message) -> str:
"""Gets the appropriate prefix for a command.
This is called by discord.py and must be async
This is called by discord.py and MUST be async

Args:
message (discord.Message): the message to check against

Returns:
str: The string of the command prefix by the bot, for the given guild
"""
guild_config = self.guild_configs[str(message.guild.id)]
return getattr(
Expand Down
11 changes: 9 additions & 2 deletions techsupport_bot/botlogging/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,14 @@

class LogLevel(Enum):
"""This is a way to map log levels to strings, and have the easy ability
to dynamically add or remove log levels"""
to dynamically add or remove log levels

Attrs:
DEBUG (str): Representation of debug
INFO (str): Representation of info
WARNING (str): Representation of warning
ERROR (str): Representation of error
"""

DEBUG = "debug"
INFO = "info"
Expand All @@ -23,7 +30,7 @@ class LogContext:
"""A very simple class to store a few contextual items about the log
This is used to determine if some guild settings means the log shouldn't be logged

Args:
Attrs:
guild (discord.Guild | None): The guild the log occured with. Optional
channel (discord.abc.Messageble | None): The channel, DM, thread,
or other messagable the log occured in
Expand Down
15 changes: 10 additions & 5 deletions techsupport_bot/botlogging/delayed.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,13 @@

class DelayedLogger(logger.BotLogger):
"""Logging interface that queues log events to be sent over time.
wait_time (float): the time to wait between log sends
queue_size (int): the max number of queue events

Args:
bot (bot.TechSupportBot): the bot object
name (str): the name of the logging channel
send (bool): Whether or not to allow sending of logs to discord
wait_time (float): the time to wait between log sends
queue_size (int): the max number of queue events
*args (tuple): The args dict passed to this, for use passing to the main logger
**kwargs (dict[str, Any]): The kwargs dict passed to this,
for use passing to the main logger
"""

def __init__(self: Self, *args: tuple, **kwargs: dict[str, Any]) -> None:
Expand All @@ -30,6 +30,11 @@ async def send_log(self: Self, *args: tuple, **kwargs: dict[str, Any]) -> None:
"""Adds a log to the queue
Does nothing different than the Logger send_log function()
Will disregard debug logs if debug is off

Args:
*args (tuple): The args dict passed to this, for use passing to the main logger
**kwargs (dict[str, Any]): The kwargs dict passed to this,
for use passing to the main logger
"""

if kwargs.get("level", None) == logger.LogLevel.DEBUG and not bool(
Expand Down
39 changes: 34 additions & 5 deletions techsupport_bot/botlogging/embed.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,16 @@


class LogEmbed(discord.Embed):
"""Base log event embed."""
"""Base log event embed.
Do not create this directly

Args:
message (str): The message to log. Will become the description of an embed

Attrs:
title (str): The title of the embed
color (discord.Color): The color of the embed
"""

title = None
color = None
Expand Down Expand Up @@ -38,28 +47,48 @@ def modify_embed(self: Self, embed: discord.Embed) -> discord.Embed:


class InfoEmbed(LogEmbed):
"""Embed for info level log events."""
"""Embed for info level log events.

Attrs:
title (str): The title of the embed
color (discord.Color): The color of the embed
"""

title = "info"
color = discord.Color.green()


class DebugEmbed(LogEmbed):
"""Embed for debug level log events."""
"""Embed for debug level log events.

Attrs:
title (str): The title of the embed
color (discord.Color): The color of the embed
"""

title = "debug"
color = discord.Color.dark_green()


class WarningEmbed(LogEmbed):
"""Embed for warning level log events."""
"""Embed for warning level log events.

Attrs:
title (str): The title of the embed
color (discord.Color): The color of the embed
"""

title = "warning"
color = discord.Color.gold()


class ErrorEmbed(LogEmbed):
"""Embed for error level log events."""
"""Embed for error level log events.

Attrs:
title (str): The title of the embed
color (discord.Color): The color of the embed
"""

title = "error"
color = discord.Color.red()
14 changes: 13 additions & 1 deletion techsupport_bot/botlogging/logger.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ class BotLogger:
"""Logging interface for Discord bots.

Args:
bot (bot.TechSupportBot): the bot object
discord_bot (bot.TechSupportBot): the bot object
name (str): the name of the logging channel
send (bool): Whether or not to allow sending of logs to discord
"""
Expand All @@ -40,6 +40,9 @@ def __init__(self: Self) -> None:
class DebugLogLevel(GenericLogLevel):
"""This is class defining special parameters for debug logs
This should never be used manually. Use the LogLevel Enum instead

Args:
main_console (logging.Logger): The console object to print logs to
"""

def __init__(self: Self, main_console: logging.Logger) -> None:
Expand All @@ -50,6 +53,9 @@ def __init__(self: Self, main_console: logging.Logger) -> None:
class InfoLogLevel(GenericLogLevel):
"""This is class defining special parameters for info logs
This should never be used manually. Use the LogLevel Enum instead

Args:
main_console (logging.Logger): The console object to print logs to
"""

def __init__(self: Self, main_console: logging.Logger) -> None:
Expand All @@ -60,6 +66,9 @@ def __init__(self: Self, main_console: logging.Logger) -> None:
class WarningLogLevel(GenericLogLevel):
"""This is class defining special parameters for warning logs
This should never be used manually. Use the LogLevel Enum instead

Args:
main_console (logging.Logger): The console object to print logs to
"""

def __init__(self: Self, main_console: logging.Logger) -> None:
Expand All @@ -70,6 +79,9 @@ def __init__(self: Self, main_console: logging.Logger) -> None:
class ErrorLogLevel(GenericLogLevel):
"""This is class defining special parameters for error logs
This should never be used manually. Use the LogLevel Enum instead

Args:
main_console (logging.Logger): The console object to print logs to
"""

def __init__(self: Self, main_console: logging.Logger) -> None:
Expand Down
9 changes: 8 additions & 1 deletion techsupport_bot/commands/animal.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,14 @@ async def setup(bot: bot.TechSupportBot) -> None:


class Animals(cogs.BaseCog):
"""The class for the animals commands"""
"""The class for the animals commands

Attrs:
CAT_API_URL (str): The URL for the cat API
DOG_API_URL (str): The URL for the dog API
FOX_API_URL (str): The URL for the fox API
FROG_API_URL (str): The URL for the frog API
"""

CAT_API_URL = "https://api.thecatapi.com/v1/images/search?limit=1&api_key={}"
DOG_API_URL = "https://dog.ceo/api/breeds/image/random"
Expand Down
15 changes: 13 additions & 2 deletions techsupport_bot/commands/application.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,14 @@

class ApplicationStatus(Enum):
"""Static string mapping of all status
This is so the database can always be consistent"""
This is so the database can always be consistent

Attrs:
PENDING (str): The string representation for pending
APPROVED (str): The string representation for approved
DENIED (str): The string representation for denied
REJECTED (str): The string representation for rejected
"""

PENDING = "pending"
APPROVED = "approved"
Expand Down Expand Up @@ -189,7 +196,11 @@ async def wait(self: Self, config: munch.Munch, guild: discord.Guild) -> None:


class ApplicationManager(cogs.LoopCog):
"""This cog is responsible for the majority of functions in the application system"""
"""This cog is responsible for the majority of functions in the application system

Attrs:
application_group (app_commands.Group): The group for the /application commands
"""

application_group = app_commands.Group(
name="application", description="...", extras={"module": "application"}
Expand Down
6 changes: 5 additions & 1 deletion techsupport_bot/commands/burn.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,11 @@ async def setup(bot: bot.TechSupportBot) -> None:


class Burn(cogs.BaseCog):
"""Class for Burn command on the discord bot."""
"""Class for Burn command on the discord bot.

Attrs:
PHRASES (list[str]): The list of phrases to pick from
"""

PHRASES = [
"Sick BURN!",
Expand Down
7 changes: 6 additions & 1 deletion techsupport_bot/commands/chatgpt.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,12 @@ async def setup(bot: bot.TechSupportBot) -> None:


class ChatGPT(cogs.BaseCog):
"""Main extension class"""
"""Main extension class

Attrs:
API_URL (str): The URL for the openai API
SYSTEM_PROMPT (dict[str, str]): The default starting prompt for chatGPT
"""

API_URL = "https://api.openai.com/v1/chat/completions"

Expand Down
Loading