Sprechender Download-Dateiname statt immer 'tuxflotte-installationsmedium.iso'

Live-Fund beim Self-Service-Flow-Test: bei mehreren Bau-Durchlaeufen/
Workspaces war der Download-Dateiname nicht unterscheidbar. Jetzt
zusammengesetzt aus Backend+Version+Workspace (aus der verwendeten
Bereitstellungsvorlage) + Bau-Datum, z.B.
'tuxflotte-Linux-Mint-22-Entwickler-2026-08-28.iso'.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Thomas Stallinger 2026-08-28 11:02:58 +02:00
parent 117e03cd23
commit fe2a893fbf

View File

@ -1,3 +1,4 @@
import re
from datetime import datetime, timedelta, timezone from datetime import datetime, timedelta, timezone
from fastapi import APIRouter, Depends, Form, HTTPException, Request from fastapi import APIRouter, Depends, Form, HTTPException, Request
@ -13,6 +14,18 @@ from templating import templates
router = APIRouter() router = APIRouter()
def _dateikomponente(text: str) -> str:
"""
Bereinigt einen Textbaustein fuer den Einsatz in einem Download-
Dateinamen (Leerzeichen/Umlaute/Sonderzeichen -> Bindestrich) - live
gefunden: der Download hiess immer nur 'tuxflotte-installationsmedium.iso',
bei mehreren Bau-Durchlaeufen/Workspaces kaum auseinanderzuhalten.
"""
bereinigt = re.sub(r"[^A-Za-z0-9]+", "-", text).strip("-")
return bereinigt or "unbekannt"
def fetch_konfiguration(organization_id: str) -> dict | None: def fetch_konfiguration(organization_id: str) -> dict | None:
with get_database_connection() as conn: with get_database_connection() as conn:
with conn.cursor() as cur: with conn.cursor() as cur:
@ -275,6 +288,23 @@ def installationsmedium_download(user=Depends(get_current_user)):
if iso_build["status"] != "completed": if iso_build["status"] != "completed":
raise HTTPException(status_code=409, detail="Das Installationsmedium ist noch nicht fertig gebaut.") raise HTTPException(status_code=409, detail="Das Installationsmedium ist noch nicht fertig gebaut.")
# Sprechender Dateiname statt immer desselben generischen Namens (siehe
# _dateikomponente()) - Backend+Version+Workspace aus der verwendeten
# Bereitstellungsvorlage, Datum aus dem Bau-Abschluss.
vorlagen_result = anode_request("GET", f"/api/v1/organizations/{organization_id}/bereitstellungsvorlagen")
vorlagen = vorlagen_result.get("bereitstellungsvorlagen", []) if vorlagen_result.get("success") else []
vorlage = next((v for v in vorlagen if v["id"] == konfiguration["bereitstellungsvorlage_id"]), None)
if vorlage:
backend_teil = _dateikomponente(f"{vorlage['backend']['name']}-{vorlage['backend']['version']}")
workspace_teil = _dateikomponente(vorlage["workspace"]["name"])
else:
backend_teil = "unbekannt"
workspace_teil = "unbekannt"
datum_teil = (iso_build.get("finished_at") or datetime.now(timezone.utc).isoformat())[:10]
dateiname = f"tuxflotte-{backend_teil}-{workspace_teil}-{datum_teil}.iso"
def stream_datei(): def stream_datei():
with anode_stream("GET", f"/api/v1/iso-builds/{build_id}/download") as response: with anode_stream("GET", f"/api/v1/iso-builds/{build_id}/download") as response:
response.raise_for_status() response.raise_for_status()
@ -284,5 +314,5 @@ def installationsmedium_download(user=Depends(get_current_user)):
return StreamingResponse( return StreamingResponse(
stream_datei(), stream_datei(),
media_type="application/octet-stream", media_type="application/octet-stream",
headers={"Content-Disposition": 'attachment; filename="tuxflotte-installationsmedium.iso"'}, headers={"Content-Disposition": f'attachment; filename="{dateiname}"'},
) )