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