feat: add upload file route
parent
7bd1e55a46
commit
7b67922a96
@ -0,0 +1,14 @@
|
||||
from sqlalchemy import Column, Integer, String, Text
|
||||
from src.database.core import Base
|
||||
from src.models import DefaultMixin, IdentityMixin
|
||||
|
||||
|
||||
class UploadedFileData(Base, DefaultMixin, IdentityMixin):
|
||||
__tablename__ = "lcc_uploaded_file"
|
||||
|
||||
filename = Column(String, nullable=False)
|
||||
file_content = Column(Text, nullable=False)
|
||||
file_url = Column(String, nullable=False)
|
||||
file_size = Column(Integer, nullable=False)
|
||||
file_type = Column(String, nullable=False)
|
||||
|
||||
@ -0,0 +1,141 @@
|
||||
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 = uploaded_file.size or 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."}],
|
||||
)
|
||||
|
||||
await delete(db_session=db_session, uploaded_file_id=uploaded_file_id)
|
||||
|
||||
return StandardResponse(message="Data deleted successfully", data=uploaded_file)
|
||||
@ -0,0 +1,30 @@
|
||||
from datetime import datetime
|
||||
from typing import List, Optional
|
||||
from uuid import UUID
|
||||
|
||||
from pydantic import Field
|
||||
from src.models import DefaultBase, Pagination
|
||||
|
||||
class UploadedFileDataBase(DefaultBase):
|
||||
filename: str = Field(..., nullable=False)
|
||||
file_content: str = Field(..., nullable=False)
|
||||
file_url: str = Field(..., nullable=False)
|
||||
file_size: int = Field(..., nullable=False)
|
||||
file_type: str = Field(..., nullable=False)
|
||||
created_at: Optional[datetime] = Field(None, nullable=True)
|
||||
updated_at: Optional[datetime] = Field(None, nullable=True)
|
||||
created_by: Optional[str] = Field(None, nullable=True)
|
||||
updated_by: Optional[str] = Field(None, nullable=True)
|
||||
|
||||
class UploadedFileDataCreate(UploadedFileDataBase):
|
||||
pass
|
||||
|
||||
class UploadedFileDataUpdate(UploadedFileDataBase):
|
||||
pass
|
||||
|
||||
class UploadedFileDataRead(UploadedFileDataBase):
|
||||
id: UUID
|
||||
wlc_version: Optional[str] = Field(None, nullable=False)
|
||||
|
||||
class UploadedFileDataPagination(Pagination):
|
||||
items: List[UploadedFileDataRead] = []
|
||||
@ -0,0 +1,66 @@
|
||||
from sqlalchemy import Select, Delete, cast, String
|
||||
from src.uploaded_file.model import UploadedFileData
|
||||
from src.uploaded_file.schema import UploadedFileDataCreate, UploadedFileDataUpdate
|
||||
from src.database.service import search_filter_sort_paginate
|
||||
from typing import Optional
|
||||
|
||||
from src.database.core import DbSession
|
||||
from src.auth.service import CurrentUser
|
||||
|
||||
|
||||
async def get(*, db_session: DbSession, uploaded_file_id: str) -> Optional[UploadedFileData]:
|
||||
"""Returns a document based on the given document id."""
|
||||
query = Select(UploadedFileData).filter(UploadedFileData.id == uploaded_file_id)
|
||||
result = await db_session.execute(query)
|
||||
return result.scalars().one_or_none()
|
||||
|
||||
|
||||
async def get_all(
|
||||
*,
|
||||
db_session: DbSession,
|
||||
items_per_page: Optional[int],
|
||||
search: Optional[str] = None,
|
||||
common,
|
||||
):
|
||||
"""Returns all documents."""
|
||||
query = Select(UploadedFileData).order_by(UploadedFileData.created_at.desc())
|
||||
if search:
|
||||
query = query.filter(cast(UploadedFileData.filename, String).ilike(f"%{search}%"))
|
||||
|
||||
common["items_per_page"] = items_per_page
|
||||
results = await search_filter_sort_paginate(model=query, **common)
|
||||
|
||||
# return results.scalars().all()
|
||||
return results
|
||||
|
||||
|
||||
async def create(*, db_session: DbSession, uploaded_file_in: UploadedFileDataCreate):
|
||||
"""Creates a new document."""
|
||||
uploaded_file = UploadedFileData(**uploaded_file_in.model_dump())
|
||||
db_session.add(uploaded_file)
|
||||
await db_session.commit()
|
||||
return uploaded_file
|
||||
|
||||
|
||||
async def update(
|
||||
*, db_session: DbSession, uploaded_file: UploadedFileData, uploaded_file_in: UploadedFileDataUpdate
|
||||
):
|
||||
"""Updates a document."""
|
||||
data = uploaded_file_in.model_dump()
|
||||
|
||||
update_data = uploaded_file_in.model_dump(exclude_defaults=True)
|
||||
|
||||
for field in data:
|
||||
if field in update_data:
|
||||
setattr(uploaded_file, field, update_data[field])
|
||||
|
||||
await db_session.commit()
|
||||
|
||||
return uploaded_file
|
||||
|
||||
|
||||
async def delete(*, db_session: DbSession, uploaded_file_id: str):
|
||||
"""Deletes a document."""
|
||||
query = Delete(UploadedFileData).where(UploadedFileData.id == uploaded_file_id)
|
||||
await db_session.execute(query)
|
||||
await db_session.commit()
|
||||
Loading…
Reference in New Issue