import os import shutil from fastapi import FastAPI, Request, File, UploadFile, Form from fastapi.responses import HTMLResponse, RedirectResponse from fastapi.templating import Jinja2Templates from fastapi.staticfiles import StaticFiles app = FastAPI() # Failsafe: Create the directory inside the container if it somehow gets missed os.makedirs("static", exist_ok=True) app.mount("/static", StaticFiles(directory="static"), name="static") templates = Jinja2Templates(directory="templates") # The persistent directory for your custom code OVERLAY_DIR = "/srv" @app.get("/", response_class=HTMLResponse) async def index(request: Request): files = [] dirs = set([""]) # Always include the root directory as an option if os.path.exists(OVERLAY_DIR): for root, dirnames, filenames in os.walk(OVERLAY_DIR): # Calculate the relative directory path rel_root = os.path.relpath(root, OVERLAY_DIR) if rel_root != ".": dirs.add(rel_root) for filename in filenames: rel_path = os.path.relpath(os.path.join(root, filename), OVERLAY_DIR) files.append(rel_path) return templates.TemplateResponse("index.html", { "request": request, "files": sorted(files), "dirs": sorted(list(dirs)) # Pass the sorted directories to the template dropdown }) @app.post("/upload") async def upload_file(file: UploadFile = File(...), target_path: str = Form("")): save_dir = os.path.join(OVERLAY_DIR, target_path.strip("/")) os.makedirs(save_dir, exist_ok=True) file_location = os.path.join(save_dir, file.filename) with open(file_location, "wb+") as file_object: shutil.copyfileobj(file.file, file_object) return RedirectResponse(url="/patch-manager/", status_code=303) @app.post("/create_folder") async def create_folder(folder_path: str = Form(...)): save_dir = os.path.join(OVERLAY_DIR, folder_path.strip("/")) os.makedirs(save_dir, exist_ok=True) return RedirectResponse(url="/patch-manager/", status_code=303) @app.post("/delete") async def delete_file(filepath: str = Form(...)): target = os.path.join(OVERLAY_DIR, filepath) if os.path.exists(target): os.remove(target) target_dir = os.path.dirname(target) if not os.listdir(target_dir) and target_dir != OVERLAY_DIR: os.rmdir(target_dir) return RedirectResponse(url="/patch-manager/", status_code=303) @app.get("/edit", response_class=HTMLResponse) async def edit_file(request: Request, filepath: str): target = os.path.join(OVERLAY_DIR, filepath) content = "" if os.path.exists(target): with open(target, "r", encoding="utf-8", errors="ignore") as f: content = f.read() return templates.TemplateResponse("edit.html", {"request": request, "filepath": filepath, "content": content}) @app.post("/edit") async def save_file(filepath: str = Form(...), content: str = Form(...)): target = os.path.join(OVERLAY_DIR, filepath) if os.path.exists(target): with open(target, "w", encoding="utf-8") as f: f.write(content) return RedirectResponse(url="/patch-manager/", status_code=303)