from configparser import ConfigParser import logging import discord 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() intents.members = True intents.message_content = True bot = commands.Bot(command_prefix='!', intents=intents) logging.basicConfig(filename=DEFAULT_LOG_FILE, level=logging.INFO) logger = logging.getLogger("Kruhobot") config = ConfigParser() config.read(DEFAULT_CONFIG_FILE) async def reply_error(ctx, message: str): """ Reply to the user with an error message. :param ctx: The context of the command. :param message: The error message. """ await reply(ctx, f'**Error:** {message}') 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. """ await ctx.send(message) @bot.event async def on_ready(): logger.info(f'Logged in as {bot.user.name}') @bot.command() async def grant_role(ctx, study_group_name: str, ukco: str): """ Grant a role to the user based on the study group and UKCO. :param ctx: The context of the command. :param study_group_name: The name of the study group. :param ukco: The UKCO of the user. """ # Check study group format if not study_group_name.startswith('kruh-') or not study_group_name[5:].isdigit(): await reply_error(ctx, 'Invalid study group format.') await reply(ctx, HELP_MESSAGE) return # Check UKCO format if not ukco.isdigit() or not len(ukco) == 8: await reply_error(ctx, 'Invalid UKCO format.') await reply(ctx, HELP_MESSAGE) return for guild_id in server_ids: if study_group_name not in study_groups[guild_id]: # Check if the study group is valid for the server continue guild = bot.get_guild(guild_id) if guild is None: # Check if the guild exists continue role = discord.utils.get(guild.roles, id=study_groups[guild_id][study_group_name]) if role is None: # Check if the role exists continue author = guild.get_member(ctx.author.id) if author is None: # Check if the author is a member of the guild continue await author.add_roles(role) await reply(ctx, f'{author.mention} has been granted the [{role.name}] role on the [{guild.name}] server.') logger.info(f'Granted role [{role.name}] to [{author.mention}] in [{guild.name}] corresponding to the study group [{study_group_name}].') return await reply_error(ctx, 'Something went wrong. Please check your command and try again.') logger.error(f'Failed to grant a role to [{author.mention}] corresponding to the study group [{study_group_name}].') return async 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('!'): await reply(message.channel, HELP_MESSAGE) return False # Check if the command is recognized if not words[0] == '!grant_role': await reply_error(message.channel, 'Unrecognized command.') await reply(message.channel, HELP_MESSAGE) return False # Check if the number of arguments is correct if not len(words) == 3: await reply_error(message.channel, 'Invalid number of arguments.') await 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 not isinstance(message.channel, discord.DMChannel) or message.author == bot.user: return is_valid_command = await check_command(message) if not is_valid_command: return await bot.process_commands(message) 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) # Run the bot bot.run(TOKEN)