Exceptions and type handling done

This commit is contained in:
2023-02-16 15:44:54 +01:00
parent b285fc0668
commit 3520912aae
5 changed files with 91 additions and 41 deletions

View File

@@ -6,7 +6,8 @@ from typing import Union
from magic import Magic
from datetime import datetime, timezone
from os import makedirs, path, remove
from classes.models import Video, SearchResultsVideo
from classes.exceptions import AlbumNameNotFoundError, SearchPageInvalidError, SearchTokenInvalidError, VideoNotFoundError, VideoSearchQueryEmptyError
from classes.models import Video, SearchResultsVideo, VideoPublic
#from modules.unified_exif_reader import extract_location
from modules.security import User, get_current_active_user
from modules.app import app
@@ -15,16 +16,18 @@ from bson.objectid import ObjectId
from bson.errors import InvalidId
from pymongo import DESCENDING
from fastapi import HTTPException, UploadFile, Security
from fastapi import UploadFile, Security
from fastapi.responses import UJSONResponse, Response
from starlette.status import HTTP_204_NO_CONTENT, HTTP_400_BAD_REQUEST, HTTP_401_UNAUTHORIZED, HTTP_404_NOT_FOUND, HTTP_422_UNPROCESSABLE_ENTITY
from starlette.status import HTTP_204_NO_CONTENT
@app.post("/albums/{album}/videos", response_class=UJSONResponse, response_model=Video, description="Upload a video to album")
video_post_responses = {
404: AlbumNameNotFoundError("name").openapi
}
@app.post("/albums/{album}/videos", description="Upload a video to album", response_class=UJSONResponse, response_model=Video, responses=video_post_responses)
async def video_upload(file: UploadFile, album: str, caption: Union[str, None] = None, current_user: User = Security(get_current_active_user, scopes=["videos.write"])):
if col_albums.find_one( {"user": current_user.user, "name": album} ) is None:
raise HTTPException(status_code=HTTP_404_NOT_FOUND, detail=f"Provided album '{album}' does not exist.")
raise AlbumNameNotFoundError(album)
# if not file.content_type.startswith("video"):
# raise HTTPException(status_code=HTTP_406_NOT_ACCEPTABLE, detail="Provided file is not a video, not accepting.")
@@ -76,11 +79,15 @@ async def video_upload(file: UploadFile, album: str, caption: Union[str, None] =
{
"id": uploaded.inserted_id.__str__(),
"album": album,
"hash": "", # SHOULD BE DONE
"filename": filename
}
)
@app.get("/videos/{id}", description="Get a video by id")
video_get_responses = {
404: VideoNotFoundError("id").openapi
}
@app.get("/videos/{id}", description="Get a video by id", responses=video_get_responses)
async def video_get(id: str, current_user: User = Security(get_current_active_user, scopes=["videos.read"])):
try:
@@ -88,7 +95,7 @@ async def video_get(id: str, current_user: User = Security(get_current_active_us
if video is None:
raise InvalidId(id)
except InvalidId:
raise HTTPException(status_code=HTTP_404_NOT_FOUND, detail="Could not find a video with such id.")
raise VideoNotFoundError(id)
video_path = path.join("data", "users", current_user.user, "albums", video["album"], video["filename"])
@@ -98,7 +105,10 @@ async def video_get(id: str, current_user: User = Security(get_current_active_us
return Response(video_file, media_type=mime)
@app.put("/videos/{id}", description="Move a video into another album")
video_move_responses = {
404: VideoNotFoundError("id").openapi
}
@app.put("/videos/{id}", description="Move a video into another album", response_model=VideoPublic, responses=video_move_responses)
async def video_move(id: str, album: str, current_user: User = Security(get_current_active_user, scopes=["videos.write"])):
try:
@@ -106,10 +116,10 @@ async def video_move(id: str, album: str, current_user: User = Security(get_curr
if video is None:
raise InvalidId(id)
except InvalidId:
raise HTTPException(status_code=HTTP_404_NOT_FOUND, detail="Could not find an video with such id.")
raise VideoNotFoundError(id)
if col_albums.find_one( {"user": current_user.user, "name": album} ) is None:
raise HTTPException(status_code=HTTP_404_NOT_FOUND, detail=f"Provided album '{album}' does not exist.")
raise AlbumNameNotFoundError(album)
if path.exists(path.join("data", "users", current_user.user, "albums", album, video["filename"])):
base_name = video["filename"].split(".")[:-1]
@@ -128,11 +138,15 @@ async def video_move(id: str, album: str, current_user: User = Security(get_curr
return UJSONResponse(
{
"id": video["_id"].__str__(),
"caption": video["caption"],
"filename": filename
}
)
@app.patch("/videos/{id}", description="Change properties of a video")
video_patch_responses = {
404: VideoNotFoundError("id").openapi
}
@app.patch("/videos/{id}", description="Change properties of a video", response_model=VideoPublic, responses=video_patch_responses)
async def video_patch(id: str, caption: str, current_user: User = Security(get_current_active_user, scopes=["videos.write"])):
try:
@@ -140,18 +154,22 @@ async def video_patch(id: str, caption: str, current_user: User = Security(get_c
if video is None:
raise InvalidId(id)
except InvalidId:
raise HTTPException(status_code=HTTP_404_NOT_FOUND, detail="Could not find an video with such id.")
raise VideoNotFoundError(id)
col_videos.find_one_and_update( {"_id": ObjectId(id)}, {"$set": {"caption": caption, "dates.modified": datetime.now(tz=timezone.utc)}} )
return UJSONResponse(
{
"id": video["_id"].__str__(),
"filename": caption
"caption": video["caption"],
"filename": video["filename"]
}
)
@app.delete("/videos/{id}", description="Delete a video by id", status_code=HTTP_204_NO_CONTENT)
video_delete_responses = {
404: VideoNotFoundError("id").openapi
}
@app.delete("/videos/{id}", description="Delete a video by id", status_code=HTTP_204_NO_CONTENT, responses=video_delete_responses)
async def video_delete(id: str, current_user: User = Security(get_current_active_user, scopes=["videos.write"])):
try:
@@ -159,7 +177,7 @@ async def video_delete(id: str, current_user: User = Security(get_current_active
if video is None:
raise InvalidId(id)
except InvalidId:
raise HTTPException(status_code=HTTP_404_NOT_FOUND, detail="Could not find a video with such id.")
raise VideoNotFoundError(id)
album = col_albums.find_one( {"name": video["album"]} )
@@ -167,20 +185,25 @@ async def video_delete(id: str, current_user: User = Security(get_current_active
return Response(status_code=HTTP_204_NO_CONTENT)
@app.get("/albums/{album}/videos", description="Find a video by filename", response_class=UJSONResponse, response_model=SearchResultsVideo)
video_find_responses = {
400: SearchPageInvalidError().openapi,
404: AlbumNameNotFoundError("name").openapi,
422: VideoSearchQueryEmptyError().openapi
}
@app.get("/albums/{album}/videos", description="Find a video by filename", response_class=UJSONResponse, response_model=SearchResultsVideo, responses=video_find_responses)
async def video_find(album: str, q: Union[str, None] = None, caption: Union[str, None] = None, page: int = 1, page_size: int = 100, current_user: User = Security(get_current_active_user, scopes=["videos.list"])):
if col_albums.find_one( {"user": current_user.user, "name": album} ) is None:
raise HTTPException(status_code=HTTP_404_NOT_FOUND, detail=f"Provided album '{album}' does not exist.")
raise AlbumNameNotFoundError(album)
if page <= 0 or page_size <= 0:
raise HTTPException(status_code=HTTP_400_BAD_REQUEST, detail="Parameters 'page' and 'page_size' must be greater or equal to 1.")
raise SearchPageInvalidError()
output = {"results": []}
skip = (page-1)*page_size
if q is None and caption is None:
raise HTTPException(status_code=HTTP_422_UNPROCESSABLE_ENTITY, detail="You must provide query or caption to look for videos")
raise VideoSearchQueryEmptyError()
if q is None and caption is not None:
db_query = {"user": current_user.user, "album": album, "caption": re.compile(caption)}
@@ -206,12 +229,15 @@ async def video_find(album: str, q: Union[str, None] = None, caption: Union[str,
return UJSONResponse(output)
@app.get("/albums/{album}/videos/token", description="Find a video by token", response_class=UJSONResponse, response_model=SearchResultsVideo)
video_find_token_responses = {
401: SearchTokenInvalidError().openapi
}
@app.get("/albums/{album}/videos/token", description="Find a video by token", response_class=UJSONResponse, response_model=SearchResultsVideo, responses=video_find_token_responses)
async def video_find_token(token: str):
found_record = col_tokens.find_one( {"token": token} )
if found_record is None:
raise HTTPException(status_code=HTTP_401_UNAUTHORIZED, detail="Invalid search token.")
raise SearchTokenInvalidError()
return await video_find(q=found_record["query"], album=found_record["album"], page=found_record["page"], page_size=found_record["page_size"], current_user=pickle.loads(found_record["user"]))