Spaces:
Running
Running
File size: 1,854 Bytes
dc06d4c c6a3f44 dc06d4c c6a3f44 dc06d4c c6a3f44 dc06d4c c6a3f44 dc06d4c c6a3f44 dc06d4c | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 | import uuid
from pathlib import Path
import openpyxl
from werkzeug.utils import secure_filename
ALLOWED_EXCEL_EXTENSIONS = (".xlsx", ".xlsm")
def save_uploaded_excel(uploaded, upload_dir: Path):
"""Validate and save an uploaded Excel file with a collision-safe name."""
if not uploaded or not uploaded.filename:
raise ValueError("No file uploaded.")
filename = secure_filename(uploaded.filename)
if not filename.lower().endswith(ALLOWED_EXCEL_EXTENSIONS):
raise ValueError("Upload an .xlsx or .xlsm file.")
stem = Path(filename).stem
suffix = Path(filename).suffix
# UUID suffixes keep simultaneous users from overwriting each other.
saved_filename = f"{stem}_{uuid.uuid4().hex[:8]}{suffix}"
destination = upload_dir / saved_filename
uploaded.save(destination)
return saved_filename, destination
def read_workbook_sheets(path: Path) -> list[str]:
"""Read sheet names without loading workbook cell data into memory."""
workbook = openpyxl.load_workbook(path, read_only=True, data_only=False)
try:
return workbook.sheetnames
finally:
workbook.close()
def resolve_allowed_path(raw_path: str, app_root: Path, allowed_roots: list[Path]) -> Path:
"""Resolve a user-supplied path and ensure it stays inside allowed roots."""
if not raw_path:
raise ValueError("Path is required.")
candidate = Path(raw_path)
if not candidate.is_absolute():
candidate = app_root / candidate
resolved = candidate.resolve()
allowed = [root.resolve() for root in allowed_roots]
# Prevent download/apply endpoints from reading arbitrary server files.
if not any(resolved == root or resolved.is_relative_to(root) for root in allowed):
raise ValueError("Path is outside the application data directory.")
return resolved
|