feat: serve landing page via Jinja2 with module grid

This commit is contained in:
Oliver Hofmann 2026-04-27 08:56:03 +02:00
parent 90d7910500
commit 9e60fbb7cf
3 changed files with 96 additions and 5 deletions

View File

@ -1,4 +1,7 @@
from fastapi import FastAPI, WebSocket from fastapi import FastAPI, Request, WebSocket
from fastapi.responses import HTMLResponse
from fastapi.staticfiles import StaticFiles
from fastapi.templating import Jinja2Templates
from app.core.config import get_settings from app.core.config import get_settings
@ -9,14 +12,71 @@ app = FastAPI(
root_path=settings.APP_PREFIX, root_path=settings.APP_PREFIX,
) )
app.mount("/static", StaticFiles(directory="app/static"), name="static")
templates = Jinja2Templates(directory="app/templates")
@app.get("/") MODULES = [
async def root(): {
return {"status": "ok", "env": settings.APP_ENV} "icon": "📡",
"name": "RSS-Feed Server",
"description": "Aggregiert und verteilt Neuigkeiten der Fakultät als standardkonformen RSS 2.0 Feed.",
"status": "active",
},
{
"icon": "📅",
"name": "Kalender",
"description": "Veranstaltungen, Prüfungstermine und Fristen im iCal-Format.",
"status": "planned",
},
{
"icon": "🔔",
"name": "Benachrichtigungen",
"description": "Push-Nachrichten und WebSocket-basierte Echtzeit-Alerts für Studierende.",
"status": "planned",
},
{
"icon": "📊",
"name": "Auslastung",
"description": "Raum- und Ressourcenauslastung der Fakultät in Echtzeit.",
"status": "planned",
},
{
"icon": "📚",
"name": "Lehrveranstaltungen",
"description": "Stundenplan-API und Kursinformationen aus dem Campus-System.",
"status": "planned",
},
]
NAV_ITEMS = [
{"label": "Übersicht", "url": "/", "active": True},
{"label": "RSS-Feeds", "url": "/rss", "active": False},
{"label": "Kalender", "url": "/kalender", "active": False},
{"label": "Docs", "url": "/docs", "active": False},
]
def _db_mode() -> str:
url = settings.DATABASE_URL
return "SQLite (dev)" if url.startswith("sqlite") else "MariaDB (prod)"
@app.get("/", response_class=HTMLResponse)
async def root(request: Request):
return templates.TemplateResponse(
request,
"index.html",
{
"nav_items": NAV_ITEMS,
"modules": MODULES,
"db_mode": _db_mode(),
"app_version": "0.1.0",
},
)
@app.websocket("/ws/hello/{name}") @app.websocket("/ws/hello/{name}")
async def websocket_hello(websocket: WebSocket, name: str): async def websocket_hello(websocket: WebSocket, name: str):
await websocket.accept() await websocket.accept()
await websocket.send_text(f"Hello, {name}!") await websocket.send_text(f"Hello, {name}!")
await websocket.close() await websocket.close()

0
tests/__init__.py Normal file
View File

31
tests/test_landing.py Normal file
View File

@ -0,0 +1,31 @@
from fastapi.testclient import TestClient
from app.main import app
client = TestClient(app)
def test_landing_returns_html():
response = client.get("/")
assert response.status_code == 200
assert "text/html" in response.headers["content-type"]
def test_landing_contains_title():
response = client.get("/")
assert "University Process Hub" in response.text
def test_landing_contains_rss_module():
response = client.get("/")
assert "RSS-Feed Server" in response.text
def test_landing_navbar_links_present():
response = client.get("/")
assert "Übersicht" in response.text
assert "RSS-Feeds" in response.text
def test_landing_info_strip_shows_db_mode():
response = client.get("/")
assert "SQLite" in response.text or "MariaDB" in response.text