mirror of
https://github.com/rzmk/learnhouse.git
synced 2025-12-19 04:19:25 +00:00
feat: init files upload/get backend code
This commit is contained in:
parent
805df9b520
commit
4e539865c9
8 changed files with 271 additions and 7 deletions
|
|
@ -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"])
|
||||||
|
|
|
||||||
|
|
@ -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
40
src/routers/files.py
Normal 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)
|
||||||
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -1,4 +0,0 @@
|
||||||
from uuid import uuid4
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
111
src/services/files/pictures.py
Normal file
111
src/services/files/pictures.py
Normal 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")
|
||||||
117
src/services/files/videos.py
Normal file
117
src/services/files/videos.py
Normal 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")
|
||||||
Loading…
Add table
Add a link
Reference in a new issue