"""Oeffentliche Routen (kein Login noetig). Etappe 1: nur Startseite + Error-Handler portiert. Etappe 3: Lektionen, Software, Projekt-Katalog, Troubleshooting. Etappe 5: Drucker-Live-View. """ from flask import Blueprint, render_template, abort, session from services.auth import login_required from services.drucker_links import drucker_links bp = Blueprint("oeffentlich", __name__) @bp.route("/") def index(): return render_template("index.html") # Stubs fuer spaetere Etappen — geben 501 zurueck, damit Navigation nicht bricht. @bp.route("/lektionen") def lektionen(): """Lektions-Uebersicht — Etappe 2 minimal, Etappe 3 voll mit Status-Badges.""" from database import get_db conn = get_db() lektionen = conn.execute( "SELECT nummer, titel, onboarding, schwierigkeit FROM lektion " "WHERE aktiv = 1 ORDER BY nummer" ).fetchall() conn.close() return render_template("lektionen.html", lektionen=lektionen) @bp.route("/lektion/") def lektion_detail(nummer): """Lektion einzeln — Etappe 2 minimal, Etappe 3 mit Status-Buttons + Inline-Edit.""" from database import get_db conn = get_db() lektion = conn.execute( "SELECT nummer, titel, onboarding, aufgabe_md, tipp_md, extern_link, schwierigkeit " "FROM lektion WHERE nummer = ? AND aktiv = 1", (nummer,) ).fetchone() conn.close() if not lektion: abort(404) return render_template("lektion_detail.html", lektion=lektion) @bp.route("/software") def software(): """Software-Sektion: Karten-Uebersicht, gruppiert nach Kategorie. Etappe 3 — Karten-Konzept (Inhalt: 1-2 Saetze + Links). Die SuS lernen den Umgang mit den Tools in den Lektionen (siehe docs/lektionen-plan.md), hier nur der Katalog. """ from database import get_db conn = get_db() karten = conn.execute( "SELECT id, slug, titel, kurzbeschreibung, url, tutorial_url, " " plattform, app_store_url, play_store_url, bild_pfad, kategorie, " " (bild_blob IS NOT NULL) AS hat_bild_blob " "FROM software_seite WHERE aktiv = 1 " "ORDER BY kategorie, sortierung, titel" ).fetchall() conn.close() # Nach Kategorie gruppieren, damit das Template einfach iterieren kann gruppen = {"software": [], "app": [], "generator": []} for k in karten: gruppen.setdefault(k["kategorie"], []).append(k) return render_template("software.html", gruppen=gruppen) @bp.route("/projekte") @login_required def projekte(): """Oeffentlicher Katalog (fuer eingeloggte SuS).""" from database import get_db from services.projekte import katalog_projekte, projekt_dateien_fuer_katalog, darf_neues_anlegen eigene_id = session["profil_id"] conn = get_db() projekte_roh = katalog_projekte(conn) darf_wiederholen, sperr_grund = darf_neues_anlegen(conn, eigene_id) projekte_view = [] for p in projekte_roh: dateien = projekt_dateien_fuer_katalog(conn, p["id"]) projekte_view.append({**dict(p), "dateien": [dict(d) for d in dateien]}) conn.close() return render_template( "projekte_katalog.html", projekte=projekte_view, eigene_profil_id=eigene_id, darf_wiederholen=darf_wiederholen, wiederhol_sperr_grund=sperr_grund, ) @bp.route("/troubleshooting") def troubleshooting(): abort(501) @bp.route("/drucker") @login_required def drucker(): """Drucker-Uebersicht fuer eingeloggte SuS. Zeigt alle aktiven Drucker mit Status, Manual-/Troubleshooting-Links und einem Banner bei Sperrung. Belegung-Anzeige (heute) folgt mit Iteration B (Slot-Reservierung). """ from database import get_db from services.slots import aktuelle_belegung, naechste_slots, profil_darf_reservieren conn = get_db() drucker_liste = conn.execute( "SELECT d.id, d.name, d.modell, d.geschlossenes_gehaeuse, d.notiz, " " d.freigegeben, d.gesperrt_grund, d.manual_url, d.troubleshooting_url, " " s.status, s.job_name, s.progress_pct, s.restzeit_min, " " s.fehlermeldung, s.gepollt_am, s.manuell_gesetzt " "FROM drucker d " "LEFT JOIN drucker_status s ON s.drucker_id = d.id " "WHERE d.aktiv = 1 " "ORDER BY d.modell, d.name" ).fetchall() darf_reservieren = profil_darf_reservieren(conn, session.get("profil_id")) # Pro Drucker: Links + aktuelle Belegung + naechste 3 Slots drucker_view = [] for d in drucker_liste: links = drucker_links(d) belegung = aktuelle_belegung(conn, d["id"]) kommend = naechste_slots(conn, d["id"], n=3) drucker_view.append({ **dict(d), "manual": links["manual"], "troubleshooting": links["troubleshooting"], "belegung": dict(belegung) if belegung else None, "kommend": [dict(s) for s in kommend], }) conn.close() return render_template( "drucker.html", drucker_liste=drucker_view, darf_reservieren=darf_reservieren, )