You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

163 lines
5.6 KiB
Python

from typing import Optional
from fastapi import APIRouter, Form, HTTPException, status, Query, UploadFile, File
from .model import UploadedFileData
from src.uploaded_file.schema import UploadedFileDataCreate, UploadedFileDataUpdate, UploadedFileDataRead, UploadedFileDataPagination
from src.uploaded_file.service import get, get_all, create, update, delete
from src.database.service import CommonParameters, search_filter_sort_paginate
from src.database.core import DbSession
from src.auth.service import CurrentUser
from src.models import StandardResponse
from pathlib import Path
from uuid import uuid4
import os
from datetime import datetime
router = APIRouter()
@router.get("", response_model=StandardResponse[UploadedFileDataPagination])
async def get_uploaded_files(
db_session: DbSession,
common: CommonParameters,
items_per_page: Optional[int] = Query(5),
search: Optional[str] = Query(None),
):
"""Get all uploaded files pagination."""
uploaded_files = await get_all(
db_session=db_session,
items_per_page=items_per_page,
search=search,
common=common,
)
# return
return StandardResponse(
data=uploaded_files,
message="Data retrieved successfully",
)
@router.get("/{uploaded_file_id}", response_model=StandardResponse[UploadedFileDataRead])
async def get_uploaded_file(db_session: DbSession, uploaded_file_id: str):
uploaded_file = await get(db_session=db_session, uploaded_file_id=uploaded_file_id)
if not uploaded_file:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail="A data with this id does not exist.",
)
return StandardResponse(data=uploaded_file, message="Data retrieved successfully")
@router.post("", response_model=StandardResponse[UploadedFileDataRead])
async def create_uploaded_file(
db_session: DbSession,
current_user: CurrentUser,
filename: Optional[str] = Form(None),
file_content: str = Form(...),
uploaded_file: UploadFile = File(...),
):
"""
Accept an UploadFile along with the UploadedFileDataCreate payload.
The file bytes and filename are attached to the input model if possible,
and created_by is set from the current user.
"""
file_read = await uploaded_file.read()
file_name = filename or uploaded_file.filename
file_size = len(file_read)
file_type = uploaded_file.content_type
try:
uploaded_file.file.seek(0)
except Exception:
raise Exception("Could not process uploaded file.")
safe_name = Path(file_name).name
unique_name = f"{safe_name}"
src_dir = Path(__file__).resolve().parent.parent
timestamp = datetime.now().strftime("%Y%m%d%H%M%S")
uploads_dir = src_dir / "uploads" / timestamp
os.makedirs(str(uploads_dir), exist_ok=True)
file_path = uploads_dir / unique_name
file_path.write_bytes(file_read)
relative_path = Path(timestamp) / unique_name
file_location = relative_path.as_posix()
file_url = f"/uploads/{file_location}"
uploaded_file_in = UploadedFileDataCreate(
filename=file_name,
file_content=file_content,
file_url=file_url,
file_size=file_size,
file_type=file_type,
created_by=current_user.name,
)
uploaded_file_obj = await create(db_session=db_session, uploaded_file_in=uploaded_file_in)
return StandardResponse(data=uploaded_file_obj, message="Data created successfully")
@router.put("/{uploaded_file_id}", response_model=StandardResponse[UploadedFileDataRead])
async def update_uploaded_file(
db_session: DbSession,
uploaded_file_id: str,
uploaded_file_in: UploadedFileDataUpdate,
current_user: CurrentUser,
):
uploaded_file = await get(db_session=db_session, uploaded_file_id=uploaded_file_id)
if not uploaded_file:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail="A data with this id does not exist.",
)
uploaded_file_in.updated_by = current_user.name
return StandardResponse(
data=await update(
db_session=db_session, uploaded_file=uploaded_file, uploaded_file_in=uploaded_file_in
),
message="Data updated successfully",
)
@router.delete("/{uploaded_file_id}", response_model=StandardResponse[UploadedFileDataRead])
async def delete_uploaded_file(db_session: DbSession, uploaded_file_id: str):
uploaded_file = await get(db_session=db_session, uploaded_file_id=uploaded_file_id)
if not uploaded_file:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=[{"msg": "A data with this id does not exist."}],
)
# Attempt to delete the file on disk if a file_url is present
file_url = uploaded_file.file_url
if file_url:
try:
# file_url is stored like "/uploads/<timestamp>/<filename>"
src_dir = Path(__file__).resolve().parent.parent
file_path = src_dir / Path(file_url.lstrip("/"))
if file_path.exists():
file_path.unlink()
# try to remove the timestamp directory if it's empty
try:
file_path.parent.rmdir()
except OSError:
# not empty or cannot remove, ignore
pass
except Exception as e:
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail=f"Failed to delete file from disk: {str(e)}",
)
await delete(db_session=db_session, uploaded_file_id=uploaded_file_id)
return StandardResponse(message="Data deleted successfully", data=uploaded_file)