From fda03dff62cc7967bd279777a012a22ddaa6ad34 Mon Sep 17 00:00:00 2001 From: Parker Date: Sat, 20 Jul 2024 18:15:15 -0500 Subject: Move files to `utils` folder --- code/utils/config.py | 274 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 274 insertions(+) create mode 100644 code/utils/config.py (limited to 'code/utils/config.py') diff --git a/code/utils/config.py b/code/utils/config.py new file mode 100644 index 0000000..d411653 --- /dev/null +++ b/code/utils/config.py @@ -0,0 +1,274 @@ +import configparser +import re +import os +import validators +import sys +import discord +import openai +import logging +from colorlog import ColoredFormatter + +log_level = logging.DEBUG +log_format = ( + " %(log_color)s%(levelname)-8s%(reset)s | %(log_color)s%(message)s%(reset)s" +) + +logging.root.setLevel(log_level) +formatter = ColoredFormatter(log_format) + +stream = logging.StreamHandler() +stream.setLevel(log_level) +stream.setFormatter(formatter) + +LOG = logging.getLogger("pythonConfig") +LOG.setLevel(log_level) +LOG.addHandler(stream) + +TOKEN = None +BOT_COLOR = None +BOT_INVITE_LINK = None +FEEDBACK_CHANNEL_ID = None +BUG_CHANNEL_ID = None +SPOTIFY_CLIENT_ID = None +SPOTIFY_CLIENT_SECRET = None +APPLE_MUSIC_KEY = None +OPENAI_API_KEY = None +LAVALINK_HOST = None +LAVALINK_PORT = None +LAVALINK_PASSWORD = None + +""" +Load the config.ini file and return the contents for validation or +create a new templated config.ini file if it doesn't exist. +""" + + +def load_config(): + # Look for variables in the environment + if "TOKEN" in os.environ or "BOT_COLOR" in os.environ or "BOT_INVITE_LINK" in os.environ: + LOG.info("Detected environment variables. Checking for configuration options.") + return validate_env_vars() + else: + LOG.info("Detected local environment. Checking for config.ini file.") + + try: + with open("config.ini", "r") as f: + file_contents = f.read() + validate_config(file_contents) + + except FileNotFoundError: + config = configparser.ConfigParser() + config["BOT_INFO"] = { + "TOKEN": "", + "BOT_COLOR": "", + "BOT_INVITE_LINK": "", + "FEEDBACK_CHANNEL_ID": "", + "BUG_CHANNEL_ID": "", + } + + config["SPOTIFY"] = { + "SPOTIFY_CLIENT_ID": "", + "SPOTIFY_CLIENT_SECRET": "", + } + + config["APPLE_MUSIC"] = { + "APPLE_MUSIC_KEY": "", + } + + config["OPENAI"] = { + "OPENAI_API_KEY": "", + } + + config["LAVALINK"] = { + "HOST": "", + "PORT": "", + "PASSWORD": "", + } + + with open("config.ini", "w") as configfile: + config.write(configfile) + + sys.exit( + LOG.critical( + "Configuration file `config.ini` has been generated. Please fill out all of the necessary information. Refer to the docs for information on what a specific configuration option is." + ) + ) + + +""" +Validate all of the options in the config.ini file. +""" + + +def validate_config(file_contents): + global TOKEN, BOT_COLOR, BOT_INVITE_LINK, FEEDBACK_CHANNEL_ID, BUG_CHANNEL_ID, SPOTIFY_CLIENT_ID, SPOTIFY_CLIENT_SECRET, APPLE_MUSIC_KEY, OPENAI_API_KEY, LAVALINK_HOST, LAVALINK_PORT, LAVALINK_PASSWORD + config = configparser.ConfigParser() + config.read_string(file_contents) + + hex_pattern_one = "^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$" + hex_pattern_two = "^([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$" + + errors = 0 + + # Make sure all sections are present + if ["BOT_INFO", "SPOTIFY", "APPLE_MUSIC", "OPENAI", "LAVALINK"] != config.sections(): + sys.exit( + LOG.critical( + "Missing sections in config.ini file. Delete the file and re-run the bot to generate a blank config.ini file." + ) + ) + + if ["token","bot_color","bot_invite_link", "feedback_channel_id","bug_channel_id",] != config.options("BOT_INFO"): + sys.exit( + LOG.critical( + "Missing options in BOT_INFO section of config.ini file. Delete the file and re-run the bot to generate a blank config.ini file." + ) + ) + + if ["spotify_client_id", "spotify_client_secret"] != config.options("SPOTIFY"): + sys.exit( + LOG.critical( + "Missing options in SPOTIFY section of config.ini file. Delete the file and re-run the bot to generate a blank config.ini file." + ) + ) + + if ["apple_music_key"] != config.options("APPLE_MUSIC"): + sys.exit( + LOG.critical( + "Missing options in APPLE_MUSIC section of config.ini file. Delete the file and re-run the bot to generate a blank config.ini file." + ) + ) + + if ["openai_api_key"] != config.options("OPENAI"): + sys.exit( + LOG.critical( + "Missing options in OPENAI section of config.ini file. Delete the file and re-run the bot to generate a blank config.ini file." + ) + ) + + if ["host", "port", "password"] != config.options("LAVALINK"): + sys.exit( + LOG.critical( + "Missing options in LAVALINK section of config.ini file. Delete the file and re-run the bot to generate a blank config.ini file." + ) + ) + + # Make sure BOT_COLOR is a valid hex color + if not bool(re.match(hex_pattern_one, config["BOT_INFO"]["BOT_COLOR"])) and not bool(re.match(hex_pattern_two, config["BOT_INFO"]["BOT_COLOR"])): + LOG.error("BOT_COLOR is not a valid hex color.") + errors += 1 + else: + BOT_COLOR = discord.Color(int((config["BOT_INFO"]["BOT_COLOR"]).replace("#", ""), 16)) + + # Make sure BOT_INVITE_LINK is a valid URL + if not validators.url(config["BOT_INFO"]["BOT_INVITE_LINK"]): + LOG.error("BOT_INVITE_LINK is not a valid URL.") + errors += 1 + else: + BOT_INVITE_LINK = config["BOT_INFO"]["BOT_INVITE_LINK"] + + # Make sure FEEDBACK_CHANNEL_ID is either exactly 0 or 19 characters long + if len(config["BOT_INFO"]["FEEDBACK_CHANNEL_ID"]) != 0: + if len(config["BOT_INFO"]["FEEDBACK_CHANNEL_ID"]) != 19: + LOG.error("FEEDBACK_CHANNEL_ID is not a valid Discord channel ID.") + errors += 1 + else: + FEEDBACK_CHANNEL_ID = int(config["BOT_INFO"]["FEEDBACK_CHANNEL_ID"]) + + # Make sure BUG_CHANNEL_ID is either exactly 0 or 19 characters long + if len(config["BOT_INFO"]["BUG_CHANNEL_ID"]) != 0: + if len(config["BOT_INFO"]["BUG_CHANNEL_ID"]) != 19: + LOG.error("BUG_CHANNEL_ID is not a valid Discord channel ID.") + errors += 1 + else: + BUG_CHANNEL_ID = int(config["BOT_INFO"]["BUG_CHANNEL_ID"]) + + # Assign the rest of the variables + TOKEN = config["BOT_INFO"]["TOKEN"] + SPOTIFY_CLIENT_ID = config["SPOTIFY"]["SPOTIFY_CLIENT_ID"] + SPOTIFY_CLIENT_SECRET = config["SPOTIFY"]["SPOTIFY_CLIENT_SECRET"] + APPLE_MUSIC_KEY = config["APPLE_MUSIC"]["APPLE_MUSIC_KEY"] + OPENAI_API_KEY = config["OPENAI"]["OPENAI_API_KEY"] + LAVALINK_HOST = config["LAVALINK"]["HOST"] + LAVALINK_PORT = config["LAVALINK"]["PORT"] + LAVALINK_PASSWORD = config["LAVALINK"]["PASSWORD"] + + if errors > 0: + sys.exit( + LOG.critical( + f"Found {errors} error(s) in the config.ini file. Please fix them and try again." + ) + ) + + +""" +Validate all of the environment variables. +""" + + +def validate_env_vars(): + global TOKEN, BOT_COLOR, BOT_INVITE_LINK, FEEDBACK_CHANNEL_ID, BUG_CHANNEL_ID, SPOTIFY_CLIENT_ID, SPOTIFY_CLIENT_SECRET, APPLE_MUSIC_KEY, OPENAI_API_KEY, LAVALINK_HOST, LAVALINK_PORT, LAVALINK_PASSWORD + + hex_pattern_one = "^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$" + hex_pattern_two = "^([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$" + + errors = 0 + + # Make sure all required variables are present in the environment + required_vars = ["TOKEN", "BOT_COLOR", "BOT_INVITE_LINK", "SPOTIFY_CLIENT_ID", "SPOTIFY_CLIENT_SECRET", "APPLE_MUSIC_KEY", "OPENAI_API_KEY", "LAVALINK_HOST", "LAVALINK_PORT", "LAVALINK_PASSWORD"] + + for var in required_vars: + if var not in os.environ: + LOG.error(f"Missing environment variable: {var}") + errors += 1 + + # Make sure BOT_COLOR is a valid hex color + if not bool(re.match(hex_pattern_one, os.environ["BOT_COLOR"])) and not bool(re.match(hex_pattern_two, os.environ["BOT_COLOR"])): + LOG.error("BOT_COLOR is not a valid hex color.") + errors += 1 + else: + BOT_COLOR = discord.Color(int((os.environ["BOT_COLOR"]).replace("#", ""), 16)) + + # Make sure BOT_INVITE_LINK is a valid URL + if not validators.url(os.environ["BOT_INVITE_LINK"]): + LOG.error("BOT_INVITE_LINK is not a valid URL.") + errors += 1 + else: + BOT_INVITE_LINK = os.environ["BOT_INVITE_LINK"] + + # Make sure FEEDBACK_CHANNEL_ID is either None or 19 characters long + try: + if len(os.environ["FEEDBACK_CHANNEL_ID"]) != 19: + LOG.error("FEEDBACK_CHANNEL_ID is not a valid Discord channel ID.") + errors += 1 + else: + FEEDBACK_CHANNEL_ID = int(os.environ["FEEDBACK_CHANNEL_ID"]) + except KeyError: + FEEDBACK_CHANNEL_ID = None + + # Make sure BUG_CHANNEL_ID is either None or 19 characters long + try: + if len(os.environ["BUG_CHANNEL_ID"]) != 19: + LOG.error("BUG_CHANNEL_ID is not a valid Discord channel ID.") + errors += 1 + else: + BUG_CHANNEL_ID = int(os.environ["BUG_CHANNEL_ID"]) + except KeyError: + BUG_CHANNEL_ID = None + + if errors > 0: + sys.exit( + LOG.critical( + f"Found {errors} error(s) with environment variables. Please fix them and try again." + ) + ) + + # Assign the rest of the variables + TOKEN = os.environ["TOKEN"] + SPOTIFY_CLIENT_ID = os.environ["SPOTIFY_CLIENT_ID"] + SPOTIFY_CLIENT_SECRET = os.environ["SPOTIFY_CLIENT_SECRET"] + APPLE_MUSIC_KEY = os.environ["APPLE_MUSIC_KEY"] + OPENAI_API_KEY = os.environ["OPENAI_API_KEY"] + LAVALINK_HOST = os.environ["LAVALINK_HOST"] + LAVALINK_PORT = os.environ["LAVALINK_PORT"] + LAVALINK_PASSWORD = os.environ["LAVALINK_PASSWORD"] \ No newline at end of file -- cgit v1.2.3-70-g09d2