mirror of
https://github.com/traberph/mensa-check.git
synced 2026-10-06 18:24:45 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
02ffd68789 | ||
|
|
2ac9405f1c | ||
|
|
835a6d8b48 | ||
|
|
bc7c2280c3 | ||
|
|
cf695f1518 | ||
|
|
1597a99360 | ||
|
|
28aa4d2962 | ||
|
|
11ad5a9320 | ||
|
|
5118db82e2 | ||
|
|
e4c05f310f | ||
|
|
d6f282757e | ||
|
|
94ffe174c8 | ||
|
|
c6f8c9f912 | ||
|
|
88f942eb60 | ||
|
|
a8aefb0e62 | ||
|
|
81aa6ec59b | ||
|
|
896f13a448 | ||
|
|
076ad18f10 | ||
|
|
da365ac881 | ||
|
|
9064802962 |
@@ -0,0 +1,31 @@
|
||||
name: Ruff - Code Quality Check
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup python
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: '3.12'
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install -r requirements.txt
|
||||
|
||||
- name: Run Ruff
|
||||
run: |
|
||||
pip install ruff
|
||||
ruff format --check
|
||||
ruff check
|
||||
@@ -1 +1,3 @@
|
||||
.venv
|
||||
venv
|
||||
__pycache__
|
||||
@@ -0,0 +1,2 @@
|
||||
[lint]
|
||||
extend-select = ["I"]
|
||||
Vendored
+4
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"editor.formatOnSave": true,
|
||||
"editor.defaultFormatter": "charliermarsh.ruff"
|
||||
}
|
||||
+3
-4
@@ -1,7 +1,6 @@
|
||||
FROM python:3.12
|
||||
FROM python:3.12-alpine
|
||||
WORKDIR /app
|
||||
COPY requirements.txt ./
|
||||
RUN pip install --no-cache-dir -r requirements.txt
|
||||
|
||||
COPY requirements.txt .
|
||||
RUN pip install -r requirements.txt --no-cache-dir
|
||||
COPY src/ .
|
||||
CMD [ "fastapi", "run", "api.py" ]
|
||||
@@ -1,17 +1,17 @@
|
||||
# Spätzle check
|
||||
|
||||
Me and my colleges have been eating in the Mensa at our university for a while now. If spätzle are on the menu it was always a gamble if they are good or really bad. Until somebody told us the problem of the bad spätzle is that they are vegan (no hate against vegan products but some products just shouldn't be vegan).
|
||||
Me and my colleagues have been eating in the Mensa at our university for a while now. If spätzle are on the menu it was always a gamble if they are good or really bad. Until somebody told us the problem of the bad spätzle is that they are vegan (no hate against vegan products but some products just shouldn't be vegan).
|
||||
|
||||
|
||||
Because of the lack of eggs the spätzle are not sticking together and are just a big pile of mush.
|
||||
|
||||
Using the allergen information on the mensa website we can check if the spätzle are vegan or not and therefore can decide if one can eat them or not.
|
||||
|
||||
This project serves a simple [website](spaetzle.traberph.de) that checks the spätzle for you.
|
||||
This project serves a simple [website](https://spaetzle.traberph.de) that checks the spätzle for you.
|
||||
|
||||
## How to run
|
||||
Simply run it with docker-compose
|
||||
Simply run it with docker compose
|
||||
|
||||
```
|
||||
docker-compose up
|
||||
docker compose up
|
||||
```
|
||||
+54
-34
@@ -1,58 +1,78 @@
|
||||
from fastapi import FastAPI
|
||||
from fastapi import FastAPI, Request
|
||||
from fastapi.responses import HTMLResponse
|
||||
from fastapi.templating import Jinja2Templates
|
||||
from cachetools import cached, TTLCache
|
||||
from bs4 import BeautifulSoup
|
||||
import requests
|
||||
import logging
|
||||
import re
|
||||
|
||||
import requests
|
||||
from bs4 import BeautifulSoup
|
||||
from cachetools import TTLCache, cached
|
||||
from fastapi import FastAPI, Request
|
||||
from fastapi.responses import FileResponse, HTMLResponse
|
||||
from fastapi.templating import Jinja2Templates
|
||||
|
||||
logger = logging.getLogger("uvicorn.error")
|
||||
cache = TTLCache(maxsize=1, ttl=3600)
|
||||
app = FastAPI()
|
||||
templates = Jinja2Templates(directory="template")
|
||||
regex = re.compile(r'Spätzle <sup>([^/]*)<\/sup>')
|
||||
regex = re.compile(r"spätzle <sup>([^/]*)</sup>", re.IGNORECASE)
|
||||
|
||||
|
||||
@cached(cache)
|
||||
def checkMensa():
|
||||
print("Checking Mensa")
|
||||
logger.info("Checking Mensa")
|
||||
|
||||
url = 'https://seezeit.com/essen/speiseplaene/mensa-giessberg/'
|
||||
r = requests.get(url)
|
||||
soup = BeautifulSoup(r.text, 'html.parser')
|
||||
try:
|
||||
url = "https://seezeit.com/essen/speiseplaene/mensa-giessberg/"
|
||||
r = requests.get(url)
|
||||
soup = BeautifulSoup(r.text, "html.parser")
|
||||
|
||||
today = soup.find('a', class_='heute')['rel'][0]
|
||||
today_menu = soup.find('div', id=f'tab{today}')
|
||||
meals = today_menu.find_all('div', class_='title')
|
||||
today = soup.find("a", class_="heute")["rel"][0]
|
||||
today_menu = soup.find("div", id=f"tab{today}")
|
||||
meals = today_menu.find_all("div", class_="title")
|
||||
|
||||
spaetzle = None
|
||||
for m in meals:
|
||||
if "Spätzle" in m.text:
|
||||
spaetzle = m
|
||||
break
|
||||
spaetzle = None
|
||||
for m in meals:
|
||||
if "spätzle" in m.text.lower():
|
||||
spaetzle = m
|
||||
break
|
||||
|
||||
if spaetzle is not None:
|
||||
ingredients = re.search(regex, str(spaetzle)).group(1)
|
||||
if '28' in ingredients:
|
||||
answer = "Spätzle with egg today"
|
||||
color = "green"
|
||||
emoji = "✅"
|
||||
if spaetzle is not None:
|
||||
ingredients = re.search(regex, str(spaetzle)).group(1)
|
||||
if "28" in ingredients:
|
||||
answer = "Spätzle with egg today"
|
||||
color = "green"
|
||||
emoji = "✅"
|
||||
|
||||
else:
|
||||
answer = "WARNING: Spätzle without egg today"
|
||||
color = "red"
|
||||
emoji = "❌"
|
||||
else:
|
||||
answer = "WARNING: Spätzle without egg today"
|
||||
color = "red"
|
||||
emoji = "❌"
|
||||
else:
|
||||
answer = "No Spätzle today "
|
||||
answer = "No Spätzle today "
|
||||
color = "grey"
|
||||
emoji = "🤷"
|
||||
except Exception:
|
||||
answer = "No menu today"
|
||||
color = "grey"
|
||||
emoji = "🤷🏻♂️"
|
||||
emoji = "⛱️"
|
||||
finally:
|
||||
logger.info(f"Answer: {answer}, Color: {color}, Emoji: {emoji}")
|
||||
return answer, color, emoji
|
||||
|
||||
return answer, color, emoji
|
||||
|
||||
@app.get("/", response_class=HTMLResponse)
|
||||
async def root(request: Request):
|
||||
answer, color, emoji = checkMensa()
|
||||
return templates.TemplateResponse(
|
||||
request=request, name="main.html", context={"text": answer, "color": color , "emoji": emoji}
|
||||
request=request,
|
||||
name="main.html",
|
||||
context={"text": answer, "color": color, "emoji": emoji},
|
||||
)
|
||||
|
||||
|
||||
@app.get("/manifest.json")
|
||||
async def manifest(request: Request):
|
||||
return FileResponse(path="assets/manifest.json")
|
||||
|
||||
|
||||
@app.get("/icons/512.png")
|
||||
async def icon(request: Request):
|
||||
return FileResponse(path="assets/logo.png")
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 127 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 125 KiB |
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"name": "Spätzle Check",
|
||||
"start_url": "/",
|
||||
"icons": [
|
||||
{
|
||||
"src": "icons/512.png",
|
||||
"type": "image/png",
|
||||
"sizes": "512x512"
|
||||
}
|
||||
],
|
||||
"display": "standalone"
|
||||
}
|
||||
@@ -6,6 +6,7 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link rel="manifest" href="/manifest.json">
|
||||
|
||||
<title>{{text}} - {{emoji}}</title>
|
||||
<style>
|
||||
|
||||
Reference in New Issue
Block a user