feat: init files upload/get backend code

This commit is contained in:
swve 2022-12-12 11:08:54 +01:00
parent 805df9b520
commit 4e539865c9
8 changed files with 271 additions and 7 deletions

View file

@ -1,5 +1,5 @@
from fastapi import APIRouter from fastapi import APIRouter
from src.routers import users, auth, houses, orgs, roles from src.routers import users, auth, houses, orgs, roles, files
from src.routers.courses import chapters, collections, courses,elements from src.routers.courses import chapters, collections, courses,elements
@ -12,6 +12,7 @@ global_router.include_router(auth.router, prefix="/auth", tags=["auth"])
global_router.include_router(houses.router, prefix="/houses", tags=["houses"]) global_router.include_router(houses.router, prefix="/houses", tags=["houses"])
global_router.include_router(orgs.router, prefix="/orgs", tags=["orgs"]) global_router.include_router(orgs.router, prefix="/orgs", tags=["orgs"])
global_router.include_router(roles.router, prefix="/roles", tags=["roles"]) global_router.include_router(roles.router, prefix="/roles", tags=["roles"])
global_router.include_router(files.router, prefix="/files", tags=["files"])
global_router.include_router(courses.router, prefix="/courses", tags=["courses"]) global_router.include_router(courses.router, prefix="/courses", tags=["courses"])
global_router.include_router(chapters.router, prefix="/chapters", tags=["chapters"]) global_router.include_router(chapters.router, prefix="/chapters", tags=["chapters"])
global_router.include_router(elements.router, prefix="/elements", tags=["elements"]) global_router.include_router(elements.router, prefix="/elements", tags=["elements"])

View file

@ -47,7 +47,6 @@ async def api_delete_element(element_id: str, current_user: PublicUser = Depends
# Video Element # Video Element
@router.post("/video") @router.post("/video")
async def api_create_video_element(name: str = Form() , coursechapter_id: str = Form(), current_user: PublicUser = Depends(get_current_user), video_file: UploadFile | None = None): async def api_create_video_element(name: str = Form() , coursechapter_id: str = Form(), current_user: PublicUser = Depends(get_current_user), video_file: UploadFile | None = None):
""" """

40
src/routers/files.py Normal file
View file

@ -0,0 +1,40 @@
from fastapi import APIRouter, Depends
from src.dependencies.auth import get_current_user
from fastapi import HTTPException, status, UploadFile
from src.services.files.pictures import create_picture_file, get_picture_file
from src.services.files.videos import create_video_file, get_video_file
from src.services.users import PublicUser
router = APIRouter()
@router.post("/picture")
async def api_create_picture_file(file_object: UploadFile, current_user: PublicUser = Depends(get_current_user)):
"""
Create new picture file
"""
return await create_picture_file(file_object, "ed_123")
@router.post("/video")
async def api_create_video_file(file_object: UploadFile, current_user: PublicUser = Depends(get_current_user)):
"""
Create new video file
"""
return await create_video_file(file_object, "ed_123")
@router.get("/picture")
async def api_get_picture_file(file_id :str ,current_user: PublicUser = Depends(get_current_user)):
"""
Get picture file
"""
return await get_picture_file(file_id, current_user)
@router.get("/video")
async def api_get_video_file(file_id :str ,current_user: PublicUser = Depends(get_current_user)):
"""
Get video file
"""
return await get_video_file(file_id, current_user)

View file

@ -1,7 +1,7 @@
from pydantic import BaseModel from pydantic import BaseModel
from src.services.database import check_database, learnhouseDB from src.services.database import check_database, learnhouseDB
from src.services.security import verify_user_rights_with_roles from src.services.security import verify_user_rights_with_roles
from src.services.courses.elements.uploads import upload_video from src.services.courses.elements.uploads.videos import upload_video
from src.services.users import PublicUser from src.services.users import PublicUser
from src.services.courses.elements.elements import ElementInDB from src.services.courses.elements.elements import ElementInDB
from fastapi import HTTPException, status, UploadFile from fastapi import HTTPException, status, UploadFile

View file

@ -1,4 +0,0 @@
from uuid import uuid4

View file

@ -0,0 +1,111 @@
from uuid import uuid4
from pydantic import BaseModel
from src.services.database import check_database, learnhouseDB, learnhouseDB
from fastapi import HTTPException, status, UploadFile
from fastapi.responses import StreamingResponse
from src.services.users import PublicUser
class PhotoFile(BaseModel):
file_id: str
file_format: str
file_name: str
file_size: int
file_type: str
element_id: str
async def create_picture_file(picture_file: UploadFile, element_id: str):
await check_database()
photos = learnhouseDB["files"]
# generate file_id
file_id = str(f"file_{uuid4()}")
# get file format
file_format = picture_file.filename.split(".")[-1]
# validate file format
if file_format not in ["jpg", "jpeg", "png", "gif"]:
raise HTTPException(
status_code=status.HTTP_409_CONFLICT, detail="Picture file format not supported")
# create file
file = await picture_file.read()
# get file size
file_size = len(file)
# get file type
file_type = picture_file.content_type
# get file name
file_name = picture_file.filename
# create file object
uploadable_file = PhotoFile(
file_id=file_id,
file_format=file_format,
file_name=file_name,
file_size=file_size,
file_type=file_type,
element_id=element_id
)
# upload file to server
with open(f"content/uploads/files/pictures/{element_id}/{file_id}.{file_format}", 'wb') as f:
f.write(file)
f.close()
# insert file object into database
photo_file_in_db = photos.insert_one(uploadable_file.dict())
if not photo_file_in_db:
raise HTTPException(
status_code=status.HTTP_409_CONFLICT, detail="Photo file could not be created")
return uploadable_file
async def get_picture_object(file_id: str):
await check_database()
photos = learnhouseDB["files"]
photo_file = photos.find_one({"file_id": file_id})
if photo_file:
photo_file = PhotoFile(**photo_file)
return photo_file
else:
raise HTTPException(
status_code=status.HTTP_409_CONFLICT, detail="Photo file does not exist")
async def get_picture_file(file_id: str, current_user: PublicUser):
await check_database()
photos = learnhouseDB["files"]
photo_file = photos.find_one({"file_id": file_id})
# check media type
if photo_file.format not in ["jpg", "jpeg", "png", "gif"]:
raise HTTPException(
status_code=status.HTTP_409_CONFLICT, detail="Photo file format not supported")
# TODO : check if user has access to file
if photo_file:
# stream file
photo_file = PhotoFile(**photo_file)
file_format = photo_file.file_format
element_id = photo_file.element_id
file = open(
f"content/uploads/files/pictures/{element_id}/{file_id}.{file_format}", 'rb')
return StreamingResponse(file, media_type=photo_file.file_type)
else:
raise HTTPException(
status_code=status.HTTP_409_CONFLICT, detail="Photo file does not exist")

View file

@ -0,0 +1,117 @@
from uuid import uuid4
from pydantic import BaseModel
import os
from src.services.database import check_database, learnhouseDB, learnhouseDB
from fastapi import HTTPException, status, UploadFile
from fastapi.responses import StreamingResponse
from src.services.users import PublicUser
class VideoFile(BaseModel):
file_id: str
file_format: str
file_name: str
file_size: int
file_type: str
element_id: str
async def create_video_file(video_file: UploadFile, element_id: str):
await check_database()
files = learnhouseDB["files"]
# generate file_id
file_id = str(f"file_{uuid4()}")
# get file format
file_format = video_file.filename.split(".")[-1]
# validate file format
if file_format not in ["mp4", "webm", "ogg"]:
raise HTTPException(
status_code=status.HTTP_409_CONFLICT, detail="Video file format not supported")
# create file
file = await video_file.read()
# get file size
file_size = len(file)
# get file type
file_type = video_file.content_type
# get file name
file_name = video_file.filename
# create file object
uploadable_file = VideoFile(
file_id=file_id,
file_format=file_format,
file_name=file_name,
file_size=file_size,
file_type=file_type,
element_id=element_id
)
# create folder for element
os.mkdir(f"content/uploads/files/videos/{element_id}")
# upload file to server
with open(f"content/uploads/files/videos/{element_id}/{file_id}.{file_format}", 'wb') as f:
f.write(file)
f.close()
# insert file object into database
video_file_in_db = files.insert_one(uploadable_file.dict())
if not video_file_in_db:
raise HTTPException(
status_code=status.HTTP_409_CONFLICT, detail="Video file could not be created")
return uploadable_file
async def get_video_object(file_id: str, current_user: PublicUser):
await check_database()
photos = learnhouseDB["files"]
video_file = photos.find_one({"file_id": file_id})
if video_file:
video_file = VideoFile(**video_file)
return video_file
else:
raise HTTPException(
status_code=status.HTTP_409_CONFLICT, detail="Photo file does not exist")
async def get_video_file(file_id: str, current_user: PublicUser):
await check_database()
photos = learnhouseDB["files"]
video_file = photos.find_one({"file_id": file_id})
# check media type
if video_file.format not in ["mp4", "webm", "ogg"]:
raise HTTPException(
status_code=status.HTTP_409_CONFLICT, detail="Video file format not supported")
# TODO : check if user has access to file
if video_file:
# stream file
video_file = VideoFile(**video_file)
file_format = video_file.file_format
element_id = video_file.element_id
def iterfile(): #
#
with open(f"content/uploads/files/videos/{element_id}/{file_id}.{file_format}", mode="rb") as file_like:
yield from file_like
return StreamingResponse(iterfile(), media_type=video_file.file_type)
else:
raise HTTPException(
status_code=status.HTTP_409_CONFLICT, detail="Video file does not exist")