import json import asyncio from init import db, Meals, scheduler, flaskApp import datetime import time import httpx nomeal = 'Essen nicht (mehr) verfügbar' async def getMeals(day: datetime): """ Liefert alle Mahlzeiten eines Tages. \n Befinden sie sich schon in der Datenbank, werden diese zurückgegeben. \n Wenn nicht, wird getMealsFromAPI() aufgerufen. \n :param day: :return [Name1, Name2, ...]: """ day = formatDay(day) essen = [] query = Meals.query.filter_by(date=day).all() if len(query) != 0: for i in query: essen += [i.name] essen.sort(key=len, reverse=True) return essen return await getMealsFromAPI(day, dbentry=True) async def getMealsFromAPI(day: str, dbentry: bool = False): """ Fragt die Mensa-API nach den Mahlzeiten eines Tages ab. \n Wenn dbentry: Schreibt die Ergebnisse in die Datenbank. \n TODO: Andere Mensen berücksichtigen. :param day: :param dbentry: :return [Name1, Name2, ...]: """ async with httpx.AsyncClient() as s: response = await s.get(url=f"https://dh-api.paulmartin.cloud/plans/{day}?canteens=erzberger") response = response.content jsonResponse = json.loads(response.decode("utf-8")) essen = [] try: number = len(jsonResponse["data"][0]["lines"]) for i in range(number): try: jsonMeals = jsonResponse["data"][0]["lines"][i]["meals"] hasContent = True except IndexError: essen = [] hasContent = False if hasContent: for e in range(len(jsonMeals)): jsonEntry = jsonMeals[e] name = jsonEntry["name"] if pricetofloat(jsonEntry["price"]) >= 1.1: vegan = jsonEntry["classifiers"].count("VG") == 1 schwein = jsonEntry["classifiers"].count("S") == 1 if vegan: vegetarian = True else: vegetarian = jsonEntry["classifiers"].count("VEG") == 1 if vegetarian: if name.count("Reibekäse") > 0: vegan = True essen += [name] if dbentry: mid = int(time.time() * 1000) % 100000 neu = Meals(date=day, name=name, id=mid, vegan=vegan, vegetarian=vegetarian, schwein=schwein) db.session.add(neu) db.session.commit() if not essen: essen = [nomeal] except KeyError: essen = [nomeal] return essen def pricetofloat(price: str): """ Konvertiert den Preis-String der Mensa-API zu einem Python-Float. :param price: :return float: """ price = price[:-2] price = price.replace(",", ".") try: return float(price) except ValueError: return 0 def formatDay(day: datetime): """ Füllt ein Datum mit Nullen auf. \n "2023-1-1" → "2023-01-01". :param day: :return str: """ if day.month < 10: monat = "0" + str(day.month) else: monat = str(day.month) if day.day < 10: tag = "0" + str(day.day) else: tag = str(day.day) formattedDay = str(day.year) + "-" + monat + "-" + tag return formattedDay async def refreshMeals(): """ Aktualisiert alle Mahlzeiten in der Datenbank. \n Datenbankeinträge werden ersetzt, wenn die API andere Mahlzeiten liefert. """ print("Aktualisiere Essenspläne...\n") table = Meals.query.all() dates = [] for i in table: if i.date not in dates: dates += [i.date] for i in range(len(dates)): dates[i] = formatDay(dates[i]) for i in dates: apiNames = await getMealsFromAPI(i) dbMeals = Meals.query.filter_by(date=i).all() dbNames = [] for meal in dbMeals: dbNames += [meal.name] if set(dbNames) != set(apiNames) and nomeal not in apiNames: for name in dbNames: db.session.delete(Meals.query.filter_by(date=i, name=name).first()) db.session.commit() await getMealsFromAPI(i, True) @scheduler.task('cron', id="mensaSchedule", hour='8-11', day_of_week='*', minute='*/15', week='*', second='5') def mensaSchedule(): """ Nutzt vormittags die Funktion refreshMeals(), um die Essen zu aktualisieren """ if not flaskApp.config["TESTING"]: with flaskApp.app_context(): asyncio.run(refreshMeals())