
- 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
161 lines
4.5 KiB
Python
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
|