diff --git a/main.py b/main.py index c56ce1d..b367321 100644 --- a/main.py +++ b/main.py @@ -7,7 +7,9 @@ from discord.ext import commands TOKEN = 'MTE1NDc0ODQ3MzE4MzMwNTc4OQ.Gz_Q7u.02sb2YNV_QQy7Bs19roXlB62mjoMKA6y8aubHU' # Bot token (replace with your own) DEFAULT_CONFIG_FILE = 'config.ini' # Configuration file with server IDs and study group roles DEFAULT_LOG_FILE = 'kruhobot.log' # Log file for the bot - +HELP_MESSAGE = """Usage: `!grant_role kruh-## UKCO` +- Replace `##` with your study group number +- Replace `UKCO` with your UKCO (8-digit personal number).""" # Create an instance of the bot intents = discord.Intents.default() @@ -19,39 +21,31 @@ bot = commands.Bot(command_prefix='!', intents=intents) logging.basicConfig(filename=DEFAULT_LOG_FILE, level=logging.INFO) logger = logging.getLogger("Kruhobot") - -async def reply_error(ctx: commands.Context, message: str): - await reply(ctx, f'**Error:** {message}', True) +config = ConfigParser() +config.read(DEFAULT_CONFIG_FILE) -async def reply(ctx: commands.Context, message: str): - await ctx.send(message) - - -def init(config): +async def reply_error(ctx, message: str): """ - Initialize the server IDs and study groups from the configuration file. - :param config: The configuration file. - :return: A tuple with server IDs and study groups. + Reply to the user with an error message. + :param ctx: The context of the command. + :param message: The error message. """ - def get_section_server_id(section): - return int(config[section]["server_ID"]) + await reply(ctx, f'**Error:** {message}') - server_ids = {get_section_server_id(section) for section in config.sections() if "server_ID" in config[section]} - study_groups = {server_id: dict() for server_id in server_ids} - for section in config.sections(): - server_id = get_section_server_id(section) - if server_id is None: - continue - - # Study group names are in style "kruh-XX", where XX is a two-digit number - # Iterate over all from top to bottom - for (key, value) in config.items(section): - if key.startswith('kruh-'): - study_groups[server_id][key] = int(value) - - return server_ids, study_groups +async def reply(ctx, message: str): + """ + Reply to the user. + :param ctx: The context of the command or the channel from the event handler. + :param message: The message to reply with. + """ + if isinstance(ctx, commands.Context): + await ctx.send(message) + elif isinstance(ctx, discord.abc.Messageable): + await ctx.send(message) + else: + logger.error(f'Failed to send the following message: "{message}"') @bot.event @@ -89,21 +83,82 @@ async def grant_role(ctx, study_group_name: str): return +def check_command(message): + # Split the message content into words + words = message.content.split() + + if len(words) == 0: + return False + + # Check if the message is a command + if not words[0].startswith('!'): + reply(message.channel, HELP_MESSAGE) + return False + + # Check if the command is recognized + if not words[0] == '!grant_role': + reply_error(message.channel, 'Unrecognized command.') + reply(message.channel, HELP_MESSAGE) + return False + + # Check if the number of arguments is correct + if not len(words) == 3: + reply_error(message.channel, 'Invalid number of arguments.') + reply(message.channel, HELP_MESSAGE) + return False + + # Check study group format + if not words[1].startswith('kruh-') or not words[1][5:].isdigit(): + reply_error(message.channel, 'Invalid study group format.') + reply(message.channel, HELP_MESSAGE) + return False + + if not words[2].isdigit() or not len(words[2]) == 8: + reply_error(message.channel, 'Invalid UKCO format.') + reply(message.channel, HELP_MESSAGE) + return False + + return True + + @bot.event async def on_message(message): # Check if the message is a private message and not from the bot itself - if isinstance(message.channel, discord.DMChannel) and message.author != bot.user: - # Split the message content into words - words = message.content.split() + if not isinstance(message.channel, discord.DMChannel) or message.author == bot.user: + return - # Check if the message starts with the bot's command prefix and has enough arguments - if len(words) >= 3 and words[0] == '!grant_role': - # Process the command - await bot.process_commands(message) + is_valid_command = check_command(message) + if not is_valid_command: + return + + await bot.process_commands(message) -config = ConfigParser() -config.read(DEFAULT_CONFIG_FILE) +def init(config): + """ + Initialize the server IDs and study groups from the configuration file. + :param config: The configuration file. + :return: A tuple with server IDs and study groups. + """ + def get_section_server_id(section): + return int(config[section]["server_ID"]) + + server_ids = {get_section_server_id(section) for section in config.sections() if "server_ID" in config[section]} + study_groups = {server_id: dict() for server_id in server_ids} + + for section in config.sections(): + server_id = get_section_server_id(section) + if server_id is None: + continue + + # Study group names are in style "kruh-XX", where XX is a two-digit number + # Iterate over all from top to bottom + for (key, value) in config.items(section): + if key.startswith('kruh-'): + study_groups[server_id][key] = int(value) + + return server_ids, study_groups + server_ids, study_groups = init(config)