Resolve file path, trying multiple locations
(file_path: str)
| 716 | |
| 717 | |
| 718 | def resolve_and_check_path(file_path: str) -> str: |
| 719 | """Resolve file path, trying multiple locations""" |
| 720 | base_dir = os.path.dirname( |
| 721 | os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) |
| 722 | |
| 723 | if os.path.isabs(file_path): |
| 724 | full_path = file_path |
| 725 | else: |
| 726 | # Smart path resolution: |
| 727 | # If path already starts with 'projects/', use it directly under base_dir |
| 728 | # Otherwise try output_dir first, then search in project outputs |
| 729 | |
| 730 | candidates = [] |
| 731 | |
| 732 | # If path starts with 'projects/', join directly with base_dir |
| 733 | if file_path.startswith('projects/'): |
| 734 | candidates.append(os.path.join(base_dir, file_path)) |
| 735 | else: |
| 736 | # Try base_dir/output first |
| 737 | output_dir = os.path.join(base_dir, 'output') |
| 738 | candidates.append(os.path.join(output_dir, file_path)) |
| 739 | |
| 740 | # Try base_dir directly |
| 741 | candidates.append(os.path.join(base_dir, file_path)) |
| 742 | |
| 743 | # Search in each project's output directory |
| 744 | projects_dir = os.path.join(base_dir, 'projects') |
| 745 | if os.path.exists(projects_dir): |
| 746 | try: |
| 747 | for project_name in os.listdir(projects_dir): |
| 748 | project_path = os.path.join(projects_dir, project_name) |
| 749 | if os.path.isdir(project_path): |
| 750 | # Try project/output/filename |
| 751 | candidates.append( |
| 752 | os.path.join(project_path, 'output', |
| 753 | file_path)) |
| 754 | except (OSError, PermissionError): |
| 755 | pass |
| 756 | |
| 757 | # Find first existing file |
| 758 | full_path = None |
| 759 | for candidate in candidates: |
| 760 | candidate = os.path.normpath(candidate) |
| 761 | if os.path.exists(candidate) and os.path.isfile(candidate): |
| 762 | full_path = candidate |
| 763 | break |
| 764 | |
| 765 | if not full_path: |
| 766 | # If not found, use the first candidate for error message |
| 767 | full_path = os.path.normpath( |
| 768 | candidates[0] if candidates else file_path) |
| 769 | |
| 770 | full_path = os.path.normpath(full_path) |
| 771 | |
| 772 | # Warning: Web UI is for local-only convenience (frontend/backend assumed localhost). |
| 773 | # For production, enforce strict backend file-access validation and authorization |
| 774 | # to prevent arbitrary path read/write (e.g., path traversal). |
| 775 | # TODO: Security check: ensure `full_path` is within configured allowed roots. |