diff --git a/CHANGELOG.txt b/CHANGELOG.txt index affe270..4d14337 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -1,3 +1,23 @@ +Version 5.0.0 - 2024-05-28 + +### What's Changed +- **Neue Befehle:** + - `/use_new_plan_sending_method` + - `/use_old_plan_sending_method` + +- Alle bisher experimentellen Funktionen sind jetzt vollständig integriert und erfordern nicht mehr den Befehl `/activate_experimental_features` zur Nutzung. + +- Der Bot erfordert nun die Variable `class`, die mit deiner Klasse gesetzt werden muss, bevor er aktiviert werden kann. Verwende dazu folgenden Befehl: + - `/set class ` + - **Hinweis:** Achte darauf, wie deine Klasse im Vertretungsplan geschrieben ist. Die meisten Klassen haben ein Leerzeichen zwischen Kürzel und Zahl, zum Beispiel `IT 22/5`. + + - Du kannst den Bot weiterhin in der alten Version nutzen, um alle Änderungen zu erhalten. Verwende dazu den Befehl `/use_old_plan_sending_method`, bevor du den Bot mit `/activate` aktivierst. + - **Warnung:** Befehle, die die Variable `class` benötigen, können jetzt undefiniertes Verhalten verursachen. Sieh mit `/help` nach, welche Befehle eine Klasse benötigen. + +- Der Befehl `/status` gibt nun auch aus ob Experimentelle Funktionen aktiv sind oder nicht. + +--- + Version 4.7.1-experimental.1 - 2024-05-22 ### What's Changed diff --git a/bot.py b/bot.py index aacfd8b..937cfeb 100644 --- a/bot.py +++ b/bot.py @@ -10,17 +10,18 @@ USERNAME = "bsz-et-2324" PASSWORD = "schulleiter#23" -CURRENT_VERSION = "v4.7.1-experimental.1" +CURRENT_VERSION = "v5.0.0" CURRENT_VERSION_FILE = f"{os.getenv('SETTINGS_VOLUME')}/version.txt" if __name__ == '__main__': Plan.save_settings(SUBSTITUTION_PLAN_PDF_URL, USERNAME, PASSWORD) - + @BSZ_BOT.event async def on_ready(): log.logger.info(f'Bot is ready! Logged in as {BSZ_BOT.user}') await BSZ_BOT.change_presence(activity=discord.Activity(type=discord.ActivityType.watching, name=CURRENT_VERSION)) try: + log.logger.info("Syncing commands...") synced = await BSZ_BOT.tree.sync() log.logger.info(f"Synced {len(synced)} command(s)") except Exception as e: diff --git a/bsz_bot/__init__.py b/bsz_bot/__init__.py index 546900d..5ff4a3f 100644 --- a/bsz_bot/__init__.py +++ b/bsz_bot/__init__.py @@ -1,8 +1,10 @@ from .tasks import setup_tasks from .core import BSZ_BOT -from .commands import ping, plan, get, set, reset, changelog, activate, deactivate, status, print_parsed_table_beta, activate_beta_features, deactivate_beta_features, news, feedback, help +from .commands import ping, plan, get, set, reset, changelog, activate, deactivate, status, print_parsed_table_beta, activate_beta_features, deactivate_beta_features, news, feedback, help, use_old_plan_sending_method, use_new_plan_sending_method from .helpers import Plan, log, send_update_info +BSZ_BOT.tree.add_command(use_old_plan_sending_method) +BSZ_BOT.tree.add_command(use_new_plan_sending_method) BSZ_BOT.tree.add_command(deactivate_beta_features) BSZ_BOT.tree.add_command(print_parsed_table_beta) BSZ_BOT.tree.add_command(activate_beta_features) diff --git a/bsz_bot/commands/__init__.py b/bsz_bot/commands/__init__.py index 69938ca..84d773d 100644 --- a/bsz_bot/commands/__init__.py +++ b/bsz_bot/commands/__init__.py @@ -12,4 +12,6 @@ from .deactivate_beta_features import deactivate_beta_features from .news import news from .feedback import feedback -from .help import help \ No newline at end of file +from .help import help +from .use_new_plan_sending_method import use_new_plan_sending_method +from .use_old_plan_sending_method import use_old_plan_sending_method \ No newline at end of file diff --git a/bsz_bot/commands/activate.py b/bsz_bot/commands/activate.py index db47e3f..84a72ab 100644 --- a/bsz_bot/commands/activate.py +++ b/bsz_bot/commands/activate.py @@ -3,6 +3,7 @@ @discord.app_commands.command(name="activate", description="Activates the bot") @admin_required +@needs_class async def activate(ctx : discord.Interaction): """ Activates the bot. diff --git a/bsz_bot/commands/feedback.py b/bsz_bot/commands/feedback.py index bab775f..3ed0830 100644 --- a/bsz_bot/commands/feedback.py +++ b/bsz_bot/commands/feedback.py @@ -32,7 +32,6 @@ async def async_copy(source, destination, buffer_size=1024*1024): await dst.write(chunk) @discord.app_commands.command(name="feedback", description="Write feedback to the Active Developers.") -@experimental async def feedback(ctx : discord.Interaction, msg : str): hash = secure_random_string(6) diff --git a/bsz_bot/commands/help.py b/bsz_bot/commands/help.py index f551582..c1dae90 100644 --- a/bsz_bot/commands/help.py +++ b/bsz_bot/commands/help.py @@ -2,20 +2,22 @@ from ..helpers import * commands_info = [ - {"command": "/help", "description": "Prints a list of available commands", "experimental": False, "admin": False}, - {"command": "/activate", "description": "Activates the bot", "experimental": False, "admin": True}, - {"command": "/deactivate", "description": "Deactivates the bot", "experimental": False, "admin": True}, - {"command": "/deactivate_experimental_features", "description": "Deactivates experimental features", "experimental": False, "admin": True}, - {"command": "/activate_experimental_features", "description": "Activates experimental features", "experimental": False, "admin": True}, - {"command": "/set ", "description": "Sets the specified variable to the given value", "experimental": False, "admin": True}, - {"command": "/reset", "description": "Resets all variables to their default values", "experimental": False, "admin": True}, - {"command": "/ping", "description": "Checks the bot's responsiveness", "experimental": False, "admin": False}, - {"command": "/plan", "description": "Retrieves the current plan", "experimental": False, "admin": False}, - {"command": "/get ", "description": "Retrieves the value of the specified variable", "experimental": False, "admin": False}, - {"command": "/status", "description": "Checks if the bot is currently active", "experimental": False, "admin": False}, - {"command": "/feedback ", "description": "Submits user feedback", "experimental": False, "admin": False}, - {"command": "/print_parsed_table_experimental", "description": "Displays the parsed table", "experimental": True, "admin": False}, - {"command": "/news_experimental", "description": "Retrieves the latest news", "experimental": True, "admin": False}, + {"command": "/help", "description": "Prints a list of available commands", "experimental": False, "admin": False, "needs_class": False}, + {"command": "/activate", "description": "Activates the bot", "experimental": False, "admin": True, "needs_class": True}, + {"command": "/deactivate", "description": "Deactivates the bot", "experimental": False, "admin": True, "needs_class": False}, + {"command": "/deactivate_experimental_features", "description": "Deactivates experimental features", "experimental": False, "admin": True, "needs_class": False}, + {"command": "/activate_experimental_features", "description": "Activates experimental features", "experimental": False, "admin": True, "needs_class": True}, + {"command": "/set ", "description": "Sets the specified variable to the given value", "experimental": False, "admin": True, "needs_class": False}, + {"command": "/reset", "description": "Resets all variables to their default values", "experimental": False, "admin": True, "needs_class": False}, + {"command": "/ping", "description": "Checks the bot's responsiveness", "experimental": False, "admin": False, "needs_class": False}, + {"command": "/plan", "description": "Retrieves the current plan", "experimental": False, "admin": False, "needs_class": False}, + {"command": "/get ", "description": "Retrieves the value of the specified variable", "experimental": False, "admin": False, "needs_class": False}, + {"command": "/status", "description": "Checks if the bot is currently active", "experimental": False, "admin": False, "needs_class": False}, + {"command": "/feedback ", "description": "Submits user feedback", "experimental": False, "admin": False, "needs_class": False}, + {"command": "/print_parsed_table", "description": "Displays the parsed table", "experimental": False, "admin": False, "needs_class": True}, + {"command": "/news", "description": "Retrieves the latest news", "experimental": False, "admin": False, "needs_class": True}, + {"command": "/use_new_plan_sending_method", "description": "Use the new plan sending method", "experimental": False, "admin": True, "needs_class": True}, + {"command": "/use_old_plan_sending_method", "description": "Use the old plan sending method", "experimental": False, "admin": True, "needs_class": False}, ] @discord.app_commands.command(name="help", description="Print a list of available commands.") @@ -25,6 +27,7 @@ async def help(ctx : discord.Interaction): for info in commands_info: experimental_note = " (Experimental)" if info["experimental"] else "" admin_note = " (Admin only)" if info["admin"] else "" - embed.add_field(name=f"{info['command']}{admin_note}{experimental_note}", value=f"{info['description']}", inline=False) + needs_class = " (Requires class)" if info["needs_class"] else "" + embed.add_field(name=f"{info['command']}{admin_note}{needs_class}{experimental_note}", value=f"{info['description']}", inline=False) await ctx.response.send_message(embed=embed, ephemeral=True) \ No newline at end of file diff --git a/bsz_bot/commands/news.py b/bsz_bot/commands/news.py index 6cf2f64..ef42a5b 100644 --- a/bsz_bot/commands/news.py +++ b/bsz_bot/commands/news.py @@ -2,8 +2,7 @@ import os from ..helpers import * -@discord.app_commands.command(name="news_experimental", description="Get the latest news for your class.") -@experimental +@discord.app_commands.command(name="news", description="Get the latest news for your class.") @needs_class async def news(ctx : discord.Interaction): parsed_plan = parse_table(f'{os.getenv("SETTINGS_VOLUME")}/{Plan(ctx.guild).get_file_name()}.pdf') @@ -11,7 +10,7 @@ async def news(ctx : discord.Interaction): msg = '' for event in parsed_plan: - if GuildSettings(ctx.guild).get("class") in event["class"]: + if GuildSettings(ctx.guild).get("class").replace(" ", "") in event["class"].replace(" ", ""): msg += f"```txt\nAm {event['date']} {event['day']}\nStunde: {event["hours"]}\nLehrer: {event["teacher"]}\nFach: {event["subject"]}\nRaum: {event["room"]}\nInfo: {event["info"]}\n```\n" if msg != '': diff --git a/bsz_bot/commands/plan.py b/bsz_bot/commands/plan.py index d5bf0c4..c778973 100644 --- a/bsz_bot/commands/plan.py +++ b/bsz_bot/commands/plan.py @@ -16,10 +16,22 @@ async def plan(ctx : discord.Interaction): error_code = await plan.download() if error_code != 200: s = GuildSettings(ctx.guild) - await ctx.response.send_message(embed=simple_embed(f"request: {error_code}", f"""ERROR: the pdf document could not be downloaded with: - File URL: {s.get('file_url')} - Username: {s.get('username')} - Password: {s.get('password')}""")) + await ctx.response.send_message(embed=simple_embed(f"Error: {error_code}", f"""ERROR: the pdf document could not be downloaded with: + `File URL: {s.get('file_url')}` + `Username: {s.get('username')}` + `Password: {s.get('password')}` + + Debugging tips: + + - try `/get all` to see all variables + - try changing the `file_url` with `/set file_url ` + - try changing the `username` with `/set username ` + - try changing the `password` with `/set password ` + - if you want to change a value back to default, use\n`/set (use default)` or `/reset`\n + If that doesn't work, please open an issue on the GitHub repository. + https://github.com/Katze719/BSZET_IT_BOT + + """)) return file = discord.File(f"{plan.get_file_name()}.png") diff --git a/bsz_bot/commands/print_parsed_table_beta.py b/bsz_bot/commands/print_parsed_table_beta.py index f4478d0..0a215ad 100644 --- a/bsz_bot/commands/print_parsed_table_beta.py +++ b/bsz_bot/commands/print_parsed_table_beta.py @@ -2,8 +2,7 @@ import os from ..helpers import * -@discord.app_commands.command(name="print_parsed_table_experimental", description="print the parsed table") -@experimental +@discord.app_commands.command(name="print_parsed_table", description="print the parsed table") async def print_parsed_table_beta(ctx : discord.Interaction): parsed_dict = parse_table(f'{os.getenv("SETTINGS_VOLUME")}/{GuildSettings(ctx.guild).get("output_name")}.pdf') diff --git a/bsz_bot/commands/set.py b/bsz_bot/commands/set.py index b6b38d9..f937002 100644 --- a/bsz_bot/commands/set.py +++ b/bsz_bot/commands/set.py @@ -39,6 +39,7 @@ async def set(ctx : discord.Interaction, variable_name: str, value: str): s.set('routine_channel_id', ctx.channel.id) await ctx.response.send_message(embed=simple_embed(f'Set {variable_name} and routine_channel_id', f"{variable_name} was set to {value} and routine_channel_id was set to {ctx.channel.id}"), ephemeral=True) return + await ctx.response.send_message(embed=simple_embed(f'Set {variable_name}', f"{variable_name} was set to {value}"), ephemeral=True) return await ctx.response.send_message(embed=simple_embed(f'Set {variable_name}', f"{variable_name} Does not exist!"), ephemeral=True) diff --git a/bsz_bot/commands/status.py b/bsz_bot/commands/status.py index 23279cd..1347b34 100644 --- a/bsz_bot/commands/status.py +++ b/bsz_bot/commands/status.py @@ -4,7 +4,10 @@ @discord.app_commands.command(name="status", description="Get the bot status.") async def status(ctx : discord.Interaction): s = GuildSettings(ctx.guild) - if s.get("routine") == "True" and s.get("routine_channel_id") != 0: - await ctx.response.send_message(embed=simple_embed(f'Status: Active', "The bot is currently active.")) + beta_features = "Experimental Features: Active" if s.get("beta_programm") == True else "Experimental Features: Inactive" + if s.get("routine") == True and s.get("routine_channel_id") != 0: + + + await ctx.response.send_message(embed=simple_embed(f'Status: Active', f"The bot is currently active.\n{beta_features}\nRoutine Channel: {s.get("routine_channel_id")}\nClass: {s.get("class")}")) else: - await ctx.response.send_message(embed=simple_embed(f'Status: Inactive', "The bot is currently inactive.")) + await ctx.response.send_message(embed=simple_embed(f'Status: Inactive', f"The bot is currently inactive.\n{beta_features}\nRoutine Channel: {s.get("routine_channel_id")}\nClass: {s.get("class")}")) diff --git a/bsz_bot/commands/use_new_plan_sending_method.py b/bsz_bot/commands/use_new_plan_sending_method.py new file mode 100644 index 0000000..42769e1 --- /dev/null +++ b/bsz_bot/commands/use_new_plan_sending_method.py @@ -0,0 +1,14 @@ +import discord +from ..helpers import * + +@discord.app_commands.command(name="use_new_plan_sending_method", description="Use the new plan sending method.") +@admin_required +@needs_class +async def use_new_plan_sending_method(ctx : discord.Interaction): + if GuildSettings(ctx.guild).get("class") == "unknown": + await ctx.response.send_message(embed=simple_embed('Error', "Class is not set.\n Set it with `/set class `")) + return + + GuildSettings(ctx.guild).set("use_old_plan_function", False) + + await ctx.response.send_message(embed=simple_embed(f'Using new plan sending method!')) diff --git a/bsz_bot/commands/use_old_plan_sending_method.py b/bsz_bot/commands/use_old_plan_sending_method.py new file mode 100644 index 0000000..d13de70 --- /dev/null +++ b/bsz_bot/commands/use_old_plan_sending_method.py @@ -0,0 +1,9 @@ +import discord +from ..helpers import * + +@discord.app_commands.command(name="use_old_plan_sending_method", description="Use the old plan sending method.") +@admin_required +async def use_old_plan_sending_method(ctx : discord.Interaction): + GuildSettings(ctx.guild).set("use_old_plan_function", True) + GuildSettings(ctx.guild).set("class", "unknown") + await ctx.response.send_message(embed=simple_embed(f'Using old plan sending method!')) diff --git a/bsz_bot/helpers/decorators.py b/bsz_bot/helpers/decorators.py index 9808129..7b21650 100644 --- a/bsz_bot/helpers/decorators.py +++ b/bsz_bot/helpers/decorators.py @@ -8,43 +8,102 @@ T = TypeVar('T', bound=Callable[..., Coroutine[Any, Any, Any]]) def admin_required(func: T) -> T: + """ + Decorator that checks if the user invoking the command is an admin. + + Parameters: + func (T): The function to be decorated. + + Returns: + T: The decorated function. + + Raises: + ValueError: If the context parameter is missing or not the first argument. + + Notes: + - This decorator checks if the user invoking the command has the 'administrator' permission in the guild. + - If the user is not an admin, it sends an error message to the user and returns early. + - If the user is an admin, it calls the decorated function with the given arguments and returns its result. + """ @wraps(func) async def wrapper(*args, **kwargs) -> Any: ctx = args[0] if not isinstance(ctx, discord.Interaction): raise ValueError("Context parameter missing or not first argument.") - + + logger.info(f"Checking if {ctx.user} is an admin...") if not ctx.user.guild_permissions.administrator: logger.info(f"{ctx.user} is not an admin.") await ctx.response.send_message(embed=simple_embed("Error", "You are not an admin."), ephemeral=True) return + logger.info(f"{ctx.user} is an admin.") return await func(*args, **kwargs) return wrapper def experimental(func: T) -> T: + """ + Decorator that checks if the experimental features are activated for the guild. + + Parameters: + func (T): The function to be decorated. + + Returns: + T: The decorated function. + + Raises: + ValueError: If the context parameter is missing or not the first argument. + + Notes: + - This decorator checks if the experimental features are activated for the guild by checking the "beta_programm" setting in the GuildSettings. + - If the experimental features are not activated, it sends an error message to the user and returns early. + - If the experimental features are activated, it calls the decorated function with the given arguments and returns its result. + """ @wraps(func) async def wrapper(*args, **kwargs) -> Any: ctx = args[0] if not isinstance(ctx, discord.Interaction): raise ValueError("Context parameter missing or not first argument.") + logger.info(f"Checking if {ctx.guild} has activated experimental features...") if GuildSettings(ctx.guild).get("beta_programm") != True: + logger.info(f"{ctx.guild} has not activated experimental features.") await ctx.response.send_message(embed=simple_embed('Error', "Experimental Features are not activated.")) return + logger.info(f"{ctx.guild} has activated experimental features.") return await func(*args, **kwargs) return wrapper def needs_class(func: T) -> T: + """ + Decorator that checks if the guild has set a class. + + Parameters: + func (T): The function to be decorated. + + Returns: + T: The decorated function. + + Raises: + ValueError: If the context parameter is missing or not the first argument. + + Notes: + - This decorator checks if the guild has set a class by checking the "class" setting in the GuildSettings. + - If the guild has not set a class, it sends an error message to the user and returns early. + - If the guild has set a class, it calls the decorated function with the given arguments and returns its result. + """ @wraps(func) async def wrapper(*args, **kwargs) -> Any: ctx = args[0] if not isinstance(ctx, discord.Interaction): raise ValueError("Context parameter missing or not first argument.") + logger.info(f"Checking if {ctx.guild} has set a class...") if not GuildSettings(ctx.guild).get("class"): + logger.info(f"{ctx.guild} has not set a class.") await ctx.response.send_message(embed=simple_embed('Error', "Class is not set.\n Set it with `/set class `")) return - + + logger.info(f"{ctx.guild} has set a class.") return await func(*args, **kwargs) return wrapper diff --git a/bsz_bot/helpers/settings.py b/bsz_bot/helpers/settings.py index 7e527e5..caf8cd7 100644 --- a/bsz_bot/helpers/settings.py +++ b/bsz_bot/helpers/settings.py @@ -39,6 +39,8 @@ def __init__(self, guild : discord.Guild): self.set("output_name", f"{guild.id}") self.set("beta_programm", False) self.set("class", False) + self.set("error_last_time", False) + self.set("use_old_plan_function", False) self.__backwards_compatibility_check(guild) @@ -66,6 +68,10 @@ def __backwards_compatibility_check(self, guild : discord.Guild): self.set("beta_programm", False) if not "class" in self.settings: self.set("class", False) + if not "error_last_time" in self.settings: + self.set("error_last_time", False) + if not "use_old_plan_function" in self.settings: + self.set("use_old_plan_function", False) def load_settings(self): diff --git a/bsz_bot/tasks/check_current_hour.py b/bsz_bot/tasks/check_current_hour.py index d34a161..2359ec7 100644 --- a/bsz_bot/tasks/check_current_hour.py +++ b/bsz_bot/tasks/check_current_hour.py @@ -12,7 +12,7 @@ async def get_news(id): for guild in BSZ_BOT.guilds: s = GuildSettings(guild) - if s.get("beta_programm") != True: + if s.get("use_old_plan_function") == True: continue if s.get("routine") != True: @@ -28,7 +28,7 @@ async def get_news(id): msg = '' for event in parsed_plan: - if s.get("class") in event["class"]: + if s.get("class").replace(" ", "") in event["class"].replace(" ", ""): if is_today(event["date"]) and f"{event["position"]}" == f"{id}": msg += f"Stunde: {event['hours']}\nLehrer: {event['teacher']}\nFach: {event['subject']}\nRaum: {event['room']}\nInfo: {event['info']}\n\n" diff --git a/bsz_bot/tasks/check_parsed_plan_beta.py b/bsz_bot/tasks/check_parsed_plan_beta.py index 7abafdf..9339aac 100644 --- a/bsz_bot/tasks/check_parsed_plan_beta.py +++ b/bsz_bot/tasks/check_parsed_plan_beta.py @@ -27,7 +27,7 @@ async def get_news(): for guild in BSZ_BOT.guilds: s = GuildSettings(guild) - if s.get("beta_programm") != True: + if s.get("use_old_plan_function") == True: continue if s.get("routine") != True: @@ -43,14 +43,12 @@ async def get_news(): msg = '' for event in parsed_plan: - if s.get("class") in event["class"]: + if s.get("class").replace(" ", "") in event["class"].replace(" ", ""): if is_tomorrow(event["date"]): msg += f"Stunde: {event["hours"]}\nLehrer: {event["teacher"]}\nFach: {event["subject"]}\nRaum: {event["room"]}\nInfo: {event["info"]}\n\n" if msg != '': await channel.send(embed=simple_embed('Morgen', f"```txt\n{msg}\n```")) - else: - await channel.send(embed=simple_embed('Morgen', 'Keine Neuigkeiten')) @get_news.before_loop diff --git a/bsz_bot/tasks/check_plan.py b/bsz_bot/tasks/check_plan.py index 8a23eca..c9fe4cc 100644 --- a/bsz_bot/tasks/check_plan.py +++ b/bsz_bot/tasks/check_plan.py @@ -1,48 +1,105 @@ import discord +import os from discord.ext import tasks from ..core import BSZ_BOT from ..helpers import * -@tasks.loop(minutes=5) -async def check_plan(): - """ - Asynchronous task that checks for a new plan every 5 minutes. - - This function is decorated with `@tasks.loop(minutes=5)` to run it every 5 minutes. - It checks for a new plan by creating a `Plan` object and calling its `new_plan_available()` method. - If no new plan is available, it checks if there are any errors by calling the `any_errors()` method of the `Plan` object. - If there are errors, it logs an error message with the text "check_plan failed". - If a new plan is available, it iterates through the guilds in `BSZ_BOT.guilds` and checks if the "routine" setting is enabled and if the "routine_channel_id" is not None. - If the conditions are met, it creates a `discord.File` object with the filename of the plan's image file and sends it to the specified channel using `channel.send()`. - The `simple_embed()` function is used to create an embed message with the title "Neuer Vertretungsplan!" and the file attachment. - - Parameters: - None - - Returns: - None - """ - logger.info("checking for new plans") - for guild in BSZ_BOT.guilds: - +async def check_plan__old(guild): s = GuildSettings(guild) if s.get("routine") != True or s.get("routine_channel_id") == 0: - continue + return channel = BSZ_BOT.get_channel(int(s.get("routine_channel_id"))) if not channel: - continue + return plan = Plan(guild) if not await plan.new_plan_available(): if plan.any_errors(): - await channel.send(embed=simple_embed(f"Error: {plan.get_error_code()}", f"""Could not fetch the new plan with: - `File URL: {s.get('file_url')}` - `Username: {s.get('username')}` - `Password: {s.get('password')}` - """)) + if not s.get("error_last_time"): + await channel.send(embed=simple_embed(f"Error: {plan.get_error_code()}", f"""Could not fetch the new plan with: + `File URL: {s.get('file_url')}` + `Username: {s.get('username')}` + `Password: {s.get('password')}` + + The Bot will now stop sending messages until the error is fixed. + + Debugging tips: + + - use `/plan` from now on, since the Bot stoped sending messages + - try `/get all` to see all variables + - try changing the `file_url` with `/set file_url ` + - try changing the `username` with `/set username ` + - try changing the `password` with `/set password ` + - if you want to change a value back to default, use\n`/set (use default)` or `/reset`\n + If that doesn't work, please open an issue on the GitHub repository. + https://github.com/Katze719/BSZET_IT_BOT + + """)) + s.set("error_last_time", True) logger.error(f"check_plan failed for {guild.name}") - continue + return + s.set("error_last_time", False) + return file = discord.File(f"{plan.get_file_name()}.png") await channel.send(file=file, embed=simple_embed('Neuer Vertretungsplan!', '', f"attachment://{plan.get_file_name()}.png")) + +async def check_plan__new(guild): + s = GuildSettings(guild) + if s.get("routine") != True or s.get("routine_channel_id") == 0: + return + channel = BSZ_BOT.get_channel(int(s.get("routine_channel_id"))) + if not channel: + return + + plan = Plan(guild) + + if not await plan.new_plan_available(): + if plan.any_errors(): + if not s.get("error_last_time"): + await channel.send(embed=simple_embed(f"Error: {plan.get_error_code()}", f"""Could not fetch the new plan with: + `File URL: {s.get('file_url')}` + `Username: {s.get('username')}` + `Password: {s.get('password')}` + + The Bot will now stop sending messages until the error is fixed. + + Debugging tips: + + - use `/plan` from now on, since the Bot stoped sending messages + - try `/get all` to see all variables + - try changing the `file_url` with `/set file_url ` + - try changing the `username` with `/set username ` + - try changing the `password` with `/set password ` + - if you want to change a value back to default, use\n`/set (use default)` or `/reset`\n + If that doesn't work, please open an issue on the GitHub repository. + https://github.com/Katze719/BSZET_IT_BOT + + """)) + s.set("error_last_time", True) + logger.error(f"check_plan failed for {guild.name}") + return + s.set("error_last_time", False) + return + + parsed_plan = parse_table(f'{os.getenv("SETTINGS_VOLUME")}/{Plan(guild).get_file_name()}.pdf') + + msg = '' + + for event in parsed_plan: + if s.get("class").replace(" ", "") in event["class"].replace(" ", ""): + msg += f"```txt\nAm {event['date']} {event['day']}\nStunde: {event["hours"]}\nLehrer: {event["teacher"]}\nFach: {event["subject"]}\nRaum: {event["room"]}\nInfo: {event["info"]}\n```\n" + + if msg != '': + await channel.send(embed=simple_embed(f'News for class `{s.get("class")}`', f"{msg}")) + +@tasks.loop(minutes=5) +async def check_plan(): + logger.info("checking for new plans") + for guild in BSZ_BOT.guilds: + if GuildSettings(guild).get("use_old_plan_function"): + await check_plan__old(guild) + else: + await check_plan__new(guild) + \ No newline at end of file