fix(ui): address code review feedback on inline preview
- Remove invalid type attribute from iframe elements - Add dedicated download endpoint with attachment disposition - Update download links to use new endpoint instead of preview Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com>
This commit is contained in:
@@ -578,6 +578,78 @@ def get_file_preview(
|
||||
raise HTTPException(status_code=500, detail=f"Error retrieving file preview: {str(e)}")
|
||||
|
||||
|
||||
@router.get("/files/{file_id}/download")
|
||||
@require_login
|
||||
def download_file(
|
||||
request: Request,
|
||||
file_id: int,
|
||||
version: str = Query("original", description="original or processed"),
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
"""
|
||||
Download file (original or processed version) as attachment.
|
||||
|
||||
Args:
|
||||
file_id: ID of the file
|
||||
version: "original" for tmp file, "processed" for processed file
|
||||
|
||||
Returns:
|
||||
File content as attachment download
|
||||
"""
|
||||
from fastapi.responses import FileResponse
|
||||
|
||||
try:
|
||||
# Find the file record
|
||||
file_record = db.query(FileRecord).filter(FileRecord.id == file_id).first()
|
||||
|
||||
if not file_record:
|
||||
raise HTTPException(status_code=404, detail=f"File with ID {file_id} not found")
|
||||
|
||||
if version == "original":
|
||||
# Return the original file from tmp
|
||||
if not file_record.local_filename or not os.path.exists(file_record.local_filename):
|
||||
raise HTTPException(status_code=404, detail="Original file not found on disk")
|
||||
|
||||
file_path = file_record.local_filename
|
||||
|
||||
elif version == "processed":
|
||||
# Look for processed file in /workdir/processed/
|
||||
workdir = settings.workdir
|
||||
processed_dir = os.path.join(workdir, "processed")
|
||||
|
||||
# Try to find the processed file (same hash or UUID-based naming)
|
||||
base_filename = os.path.splitext(file_record.original_filename)[0]
|
||||
potential_paths = [
|
||||
os.path.join(processed_dir, f"{file_record.filehash}.pdf"),
|
||||
os.path.join(processed_dir, f"{base_filename}_processed.pdf"),
|
||||
os.path.join(processed_dir, file_record.original_filename),
|
||||
]
|
||||
|
||||
file_path = None
|
||||
for path in potential_paths:
|
||||
if os.path.exists(path):
|
||||
file_path = path
|
||||
break
|
||||
|
||||
if not file_path:
|
||||
raise HTTPException(status_code=404, detail="Processed file not found")
|
||||
else:
|
||||
raise HTTPException(status_code=400, detail="Invalid version parameter. Use 'original' or 'processed'")
|
||||
|
||||
# Return the file with attachment disposition to trigger download
|
||||
return FileResponse(
|
||||
path=file_path,
|
||||
media_type=file_record.mime_type or "application/pdf",
|
||||
headers={"Content-Disposition": f'attachment; filename="{file_record.original_filename}"'},
|
||||
)
|
||||
|
||||
except HTTPException:
|
||||
raise
|
||||
except Exception as e:
|
||||
logger.exception(f"Error downloading file: {str(e)}")
|
||||
raise HTTPException(status_code=500, detail=f"Error downloading file: {str(e)}")
|
||||
|
||||
|
||||
@router.post("/ui-upload")
|
||||
@require_login
|
||||
async def ui_upload(request: Request, file: UploadFile = File(...)):
|
||||
|
||||
@@ -871,14 +871,14 @@
|
||||
<iframe src="/api/files/{{ file.id }}/preview?version=original" style="width: 100%; height: 600px; border: none;"></iframe>
|
||||
{% else %}
|
||||
<!-- PDF and other documents -->
|
||||
<iframe src="/api/files/{{ file.id }}/preview?version=original" type="application/pdf" style="width: 100%; height: 600px; border: none;"></iframe>
|
||||
<iframe src="/api/files/{{ file.id }}/preview?version=original" style="width: 100%; height: 600px; border: none;"></iframe>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div style="margin-top: 0.5rem; text-align: center; display: flex; gap: 1rem; justify-content: center;">
|
||||
<a href="/api/files/{{ file.id }}/preview?version=original" target="_blank" style="color: #3182ce; text-decoration: none; font-size: 0.875rem;">
|
||||
<i class="fas fa-external-link-alt"></i> Open in new tab
|
||||
</a>
|
||||
<a href="/api/files/{{ file.id }}/preview?version=original" download="{{ file.original_filename }}" style="color: #3182ce; text-decoration: none; font-size: 0.875rem;">
|
||||
<a href="/api/files/{{ file.id }}/download?version=original" style="color: #3182ce; text-decoration: none; font-size: 0.875rem;">
|
||||
<i class="fas fa-download"></i> Download
|
||||
</a>
|
||||
</div>
|
||||
@@ -890,13 +890,13 @@
|
||||
<h4 style="font-weight: 600; color: #2d3748; margin-bottom: 1rem;">Processed File</h4>
|
||||
<div style="border: 2px solid #e2e8f0; border-radius: 0.5rem; overflow: hidden; background-color: #f7fafc;">
|
||||
<!-- Processed files are typically PDFs -->
|
||||
<iframe src="/api/files/{{ file.id }}/preview?version=processed" type="application/pdf" style="width: 100%; height: 600px; border: none;"></iframe>
|
||||
<iframe src="/api/files/{{ file.id }}/preview?version=processed" style="width: 100%; height: 600px; border: none;"></iframe>
|
||||
</div>
|
||||
<div style="margin-top: 0.5rem; text-align: center; display: flex; gap: 1rem; justify-content: center;">
|
||||
<a href="/api/files/{{ file.id }}/preview?version=processed" target="_blank" style="color: #3182ce; text-decoration: none; font-size: 0.875rem;">
|
||||
<i class="fas fa-external-link-alt"></i> Open in new tab
|
||||
</a>
|
||||
<a href="/api/files/{{ file.id }}/preview?version=processed" download="{{ file.original_filename }}" style="color: #3182ce; text-decoration: none; font-size: 0.875rem;">
|
||||
<a href="/api/files/{{ file.id }}/download?version=processed" style="color: #3182ce; text-decoration: none; font-size: 0.875rem;">
|
||||
<i class="fas fa-download"></i> Download
|
||||
</a>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user