Spaces:
Running
Running
| 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 | |