main.py 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869
  1. import os
  2. import shutil
  3. from fastapi import FastAPI, Request, File, UploadFile, Form
  4. from fastapi.responses import HTMLResponse, RedirectResponse
  5. from fastapi.templating import Jinja2Templates
  6. from fastapi.staticfiles import StaticFiles
  7. # =====================================================================
  8. # MODIFICATION: ROOT PATH FOR NGINX
  9. # Why: When Nginx routes traffic from yourdomain.com/patch-manager/
  10. # to this sidecar, FastAPI needs to know its "base" URL is no longer "/".
  11. # If we don't set this, the app will try to load CSS and submit forms
  12. # to the wrong root URL, resulting in 404 errors.
  13. # =====================================================================
  14. app = FastAPI(root_path="/patch-manager")
  15. app.mount("/static", StaticFiles(directory="static"), name="static")
  16. templates = Jinja2Templates(directory="templates")
  17. OVERLAY_DIR = "/srv"
  18. @app.get("/", response_class=HTMLResponse)
  19. async def index(request: Request):
  20. files = []
  21. if os.path.exists(OVERLAY_DIR):
  22. for root, dirs, filenames in os.walk(OVERLAY_DIR):
  23. for filename in filenames:
  24. rel_path = os.path.relpath(os.path.join(root, filename), OVERLAY_DIR)
  25. files.append(rel_path)
  26. return templates.TemplateResponse("index.html", {"request": request, "files": sorted(files)})
  27. @app.post("/upload")
  28. async def upload_file(file: UploadFile = File(...), target_path: str = Form("")):
  29. save_dir = os.path.join(OVERLAY_DIR, target_path.strip("/"))
  30. os.makedirs(save_dir, exist_ok=True)
  31. file_location = os.path.join(save_dir, file.filename)
  32. with open(file_location, "wb+") as file_object:
  33. shutil.copyfileobj(file.file, file_object)
  34. # Notice we redirect to "/" here. Because we set root_path="/patch-manager",
  35. # FastAPI automatically translates this redirect to "/patch-manager/"!
  36. return RedirectResponse(url="/", status_code=303)
  37. @app.post("/delete")
  38. async def delete_file(filepath: str = Form(...)):
  39. target = os.path.join(OVERLAY_DIR, filepath)
  40. if os.path.exists(target):
  41. os.remove(target)
  42. target_dir = os.path.dirname(target)
  43. if not os.listdir(target_dir) and target_dir != OVERLAY_DIR:
  44. os.rmdir(target_dir)
  45. return RedirectResponse(url="/", status_code=303)
  46. @app.get("/edit", response_class=HTMLResponse)
  47. async def edit_file(request: Request, filepath: str):
  48. target = os.path.join(OVERLAY_DIR, filepath)
  49. content = ""
  50. if os.path.exists(target):
  51. with open(target, "r", encoding="utf-8", errors="ignore") as f:
  52. content = f.read()
  53. return templates.TemplateResponse("edit.html", {"request": request, "filepath": filepath, "content": content})
  54. @app.post("/edit")
  55. async def save_file(filepath: str = Form(...), content: str = Form(...)):
  56. target = os.path.join(OVERLAY_DIR, filepath)
  57. if os.path.exists(target):
  58. with open(target, "w", encoding="utf-8") as f:
  59. f.write(content)
  60. return RedirectResponse(url="/", status_code=303)