Automated Action b9d7b6ef54 Fix FastAPI error due to File parameter collision
- Updated the imports in files.py to use UploadFile directly instead of aliasing File to UploadedFile
- Simplified the upload_file endpoint parameter declaration to avoid conflicts
- Removed unnecessary default value for UploadFile parameter
2025-06-09 14:24:29 +00:00

161 lines
4.5 KiB
Python

from fastapi import APIRouter, Depends, UploadFile, HTTPException, status
from fastapi.responses import StreamingResponse
from sqlalchemy.orm import Session
from typing import List
from app.db.session import get_db
from app.models.file import File
from app.schemas.file import FileResponse
from app.services.file_service import FileService
router = APIRouter()
@router.post("/", response_model=FileResponse, status_code=status.HTTP_201_CREATED)
async def upload_file(
file: UploadFile,
db: Session = Depends(get_db),
):
"""
Upload a file to the server.
The file will be stored in the server's file system, and its metadata will be saved in the database.
"""
try:
# Save the file to disk
unique_filename, file_path, file_size = await FileService.save_file(file)
# Create a new file record in the database
db_file = File(
filename=unique_filename,
original_filename=file.filename or "unnamed_file",
content_type=file.content_type or "application/octet-stream",
file_size=file_size,
file_path=file_path,
)
db.add(db_file)
db.commit()
db.refresh(db_file)
# Construct the download URL
download_url = f"/api/v1/files/{db_file.id}/download"
# Return the file metadata with download URL
return {
**db_file.__dict__,
"download_url": download_url,
}
except HTTPException as e:
# Re-raise HTTP exceptions
raise e
except Exception as e:
# Log the error and return a generic error message
print(f"Error uploading file: {str(e)}")
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="An error occurred while uploading the file",
)
@router.get("/", response_model=List[FileResponse])
def list_files(db: Session = Depends(get_db)):
"""
List all files stored in the system.
Returns a list of file metadata.
"""
files = db.query(File).all()
# Add download URLs to each file
for file in files:
file.__dict__["download_url"] = f"/api/v1/files/{file.id}/download"
return files
@router.get("/{file_id}", response_model=FileResponse)
def get_file(file_id: int, db: Session = Depends(get_db)):
"""
Get metadata for a specific file by ID.
"""
file = db.query(File).filter(File.id == file_id).first()
if not file:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail="File not found",
)
# Add download URL to the file
file.__dict__["download_url"] = f"/api/v1/files/{file.id}/download"
return file
@router.get("/{file_id}/download")
def download_file(file_id: int, db: Session = Depends(get_db)):
"""
Download a file by its ID.
Returns the file as a streaming response.
"""
# Get the file metadata from the database
file = db.query(File).filter(File.id == file_id).first()
if not file:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail="File not found",
)
# Check if the file exists on disk
if not FileService.file_exists(file.filename):
# If the file does not exist on disk, update the database
db.delete(file)
db.commit()
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail="File not found on disk",
)
# Get file content
file_content = FileService.get_file_content(file.filename)
# Return the file as a streaming response
return StreamingResponse(
content=file_content,
media_type=file.content_type,
headers={
"Content-Disposition": f'attachment; filename="{file.original_filename}"',
},
)
@router.delete(
"/{file_id}", status_code=status.HTTP_204_NO_CONTENT, response_model=None
)
def delete_file(file_id: int, db: Session = Depends(get_db)):
"""
Delete a file by its ID.
Removes the file from both the database and the file system.
"""
# Get the file metadata from the database
file = db.query(File).filter(File.id == file_id).first()
if not file:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail="File not found",
)
# Delete the file from disk
FileService.delete_file(file.filename)
# Delete the file metadata from the database
db.delete(file)
db.commit()
return None