"""Wgrywanie plików: jedna czynność, nie dwie. „Dodać plik" ma tu znaczyć, że od razu bierze udział w wyszukiwaniu — inaczej po wgraniu nic by się nie zmieniło i wyglądałoby to na zepsute. Nie ma listy plików ani ich stanów: ta usługa ma jeden poziom dostępu, więc nie ma komu ich pokazywać ani po co. """ from __future__ import annotations import base64 import httpx from fastapi import File, Request, UploadFile from fastapi.responses import HTMLResponse, RedirectResponse from app.features import Feature from app.podstawa import app, features, logic, templates, _logic_error # Stan pliku „w użyciu" — ta sama nazwa, co w warstwie danych (DAN-27). Wpisana # tutaj wprost, bo ta usługa tamtej warstwy nie importuje; literówka objawiłaby # się dopiero na żywo, więc pilnuje jej test. W_UZYCIU = "active" @app.get("/pliki", response_class=HTMLResponse) def wgrywanie_form(request: Request, error: str = "", done: str = ""): return templates.TemplateResponse(request, "wgrywanie.html", {"error": error, "done": done}) @app.post("/pliki/wgraj") async def wgraj(request: Request, upload: UploadFile = File(...)): """Wgranie ORAZ włączenie do użytku. Plik o złym układzie nie wchodzi do użytku, ale NIE JEST tracony — zostaje zapisany i czeka. Komunikat nie mówi, CZYM się nie nadaje: różnica w treści byłaby wyrocznią, z której da się odczytać, czego program oczekuje. """ raw = await upload.read() if not raw: return _wroc(error="Pusty plik.") kto = getattr(request.state, "user", "") or "?" try: out = logic.files_upload(upload.filename or "dane.xlsx", base64.b64encode(raw).decode("ascii"), by=kto) except httpx.HTTPError as e: return _wroc(error=_logic_error(e)) nazwa = out.get("name") or "plik" if not out.get("accepted"): return _wroc(done=f"Plik „{nazwa}” został przyjęty, ale nie nadaje się " f"do użycia w tej postaci.") try: logic.files_status(out["path"], W_UZYCIU, by=kto) except httpx.HTTPError as e: return _wroc(error=f"Plik „{nazwa}” wgrany, ale nie udało się go włączyć.") return _wroc(done=f"Dodano „{nazwa}”. Plik jest już używany przy wyszukiwaniu.") def _wroc(error: str = "", done: str = "") -> RedirectResponse: """Po zapisie PRZEKIEROWANIE, nie render — odświeżenie strony nie może wgrać pliku drugi raz.""" from urllib.parse import urlencode q = urlencode({k: v for k, v in (("error", error), ("done", done)) if v}) return RedirectResponse(f"/pliki{'?' + q if q else ''}", status_code=303) features.zarejestruj( ekran=Feature("files", "Pliki", "Dodawanie plików używanych przy wyszukiwaniu.", "Ekrany", "/pliki", kolejnosc=70), trasy={("GET", "/pliki"): "files", ("POST", "/pliki/wgraj"): "files"}, zasoby={"s-wgrywanie.css": "files"}, )