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//" 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)