b03ebab747
Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com>
4.7 KiB
4.7 KiB
Fix for Issue: Uploaded files do not maintain original file name
Problem Summary
Users reported that files uploaded through the UI were being renamed to UUIDs during processing, making it impossible to recognize the original files. For example, a file originally named "Apostille Sverige.pdf" would appear as "e64b2825-9ff2-486b-aff1-08af2957140b.pdf" in the file detail view.
Root Cause
The issue occurred because:
- In
app/api/files.py, theui_uploadendpoint saves uploaded files with UUID-based filenames for security (to prevent path traversal and filename conflicts) - This UUID-based path is passed to the
process_documenttask - The
process_documenttask extracts the filename from the path usingos.path.basename(), which returns the UUID-based name - This UUID-based name is then stored in the database as the
original_filename
Solution Implemented
Changes Made
1. Modified app/tasks/process_document.py
- Added optional
original_filenameparameter to theprocess_documentfunction - When provided, uses the passed filename instead of extracting from path
- Falls back to
os.path.basename()when parameter is not provided (backward compatibility)
def process_document(self, original_local_file: str, original_filename: str = None):
# ...
if original_filename is None:
original_filename = os.path.basename(original_local_file)
2. Modified app/tasks/convert_to_pdf.py
- Added optional
original_filenameparameter to theconvert_to_pdffunction - Passes through the original filename to
process_documentafter conversion - Adjusts file extension to .pdf when passing to the next stage
def convert_to_pdf(self, file_path, original_filename=None):
# ...
if original_filename:
original_base = os.path.splitext(original_filename)[0]
pdf_original_filename = f"{original_base}.pdf"
process_document.delay(converted_file_path, original_filename=pdf_original_filename)
else:
process_document.delay(converted_file_path)
3. Modified app/api/files.py
- Updated
ui_uploadendpoint to pass the original safe filename to processing tasks - Passes
original_filename=safe_filenameparameter to bothprocess_documentandconvert_to_pdf
# For PDFs
task = process_document.delay(target_path, original_filename=safe_filename)
# For images and office documents
task = convert_to_pdf.delay(target_path, original_filename=safe_filename)
Testing
Unit Tests (tests/test_original_filename_preservation.py)
Created comprehensive unit tests to verify:
-
Test 1: Original filename is preserved when parameter is provided
- Uploads a file with UUID-based path but provides original filename "Apostille Sverige.pdf"
- Verifies the database stores the original filename, not the UUID-based path
-
Test 2: Backward compatibility is maintained
- Calls
process_documentwithout the optional parameter - Verifies it falls back to extracting filename from path
- Calls
All tests pass successfully.
Existing Tests
All existing tests in tests/test_process_document.py continue to pass, confirming backward compatibility.
Benefits of This Solution
- Minimal Changes: Only 3 files modified, optional parameter added to maintain backward compatibility
- Security Maintained: Files are still stored with UUID-based names on disk to prevent:
- Filename conflicts
- Path traversal attacks
- Overwriting existing files
- User Experience Improved: Users can now see their original filenames in the UI
- Backward Compatible: Existing code that calls these tasks without the new parameter continues to work
Example Flow
Before the fix:
User uploads: "Apostille Sverige.pdf"
→ Saved as: "e64b2825-9ff2-486b-aff1-08af2957140b.pdf"
→ process_document extracts: "e64b2825-9ff2-486b-aff1-08af2957140b.pdf"
→ Database stores: "e64b2825-9ff2-486b-aff1-08af2957140b.pdf" ❌
After the fix:
User uploads: "Apostille Sverige.pdf"
→ Saved as: "e64b2825-9ff2-486b-aff1-08af2957140b.pdf" (for security)
→ ui_upload passes original_filename="Apostille Sverige.pdf" to process_document
→ Database stores: "Apostille Sverige.pdf" ✅
Files Changed
app/tasks/process_document.py: Added optional parameter and logic to use itapp/tasks/convert_to_pdf.py: Added optional parameter and pass-through logicapp/api/files.py: Updated to pass original filename to taskstests/test_original_filename_preservation.py: New comprehensive unit tests
Code Quality
- All code formatted with Black (line length 120)
- All imports sorted with isort (Black profile)
- All linting issues resolved (flake8)
- All existing and new tests pass