Run black on utils

This commit is contained in:
Dion Moult
2024-07-26 12:13:29 +10:00
parent a6286293d8
commit e7b791f4a2
78 changed files with 2235 additions and 2098 deletions
+392 -252
View File
@@ -1,5 +1,5 @@
from uuid import UUID
from fastapi import APIRouter, Depends, UploadFile, HTTPException
from fastapi import APIRouter, Depends, UploadFile, HTTPException
from fastapi.responses import FileResponse
from security.secure import get_current_active_user
@@ -46,38 +46,40 @@ router = APIRouter(route_class=LoggingRoute)
@router.get("/bcf/3.0/projects", tags=["projects_get"])
def projects_get(current_user: User = Depends(get_current_active_user)) -> List[ProjectGET]:
projects_response = bcf_db.get_projects(current_user)
bcf_db.debug(endpoint='projects_get',
request={},
response={count: value.dict() for count, value in enumerate(projects_response)})
bcf_db.debug(
endpoint="projects_get",
request={},
response={count: value.dict() for count, value in enumerate(projects_response)},
)
return projects_response
@router.get("/bcf/3.0/projects/{project_id}", tags=["project_get"])
def project_get(project_id: UUID, current_user: User = Depends(get_current_active_user)) -> ProjectGET:
project_response = bcf_db.get_project(project_id, current_user)
bcf_db.debug(endpoint='project_get',
request={'project_id': project_id},
response=project_response.dict())
bcf_db.debug(endpoint="project_get", request={"project_id": project_id}, response=project_response.dict())
return project_response
@router.put("/bcf/3.0/projects/{project_id}", tags=["project_put"], status_code=200)
def project_put(project_id: UUID, project_request: ProjectPUT,
current_user: User = Depends(get_current_active_user)) -> ProjectGET:
def project_put(
project_id: UUID, project_request: ProjectPUT, current_user: User = Depends(get_current_active_user)
) -> ProjectGET:
project_response = bcf_db.put_project(project_id, project_request, current_user)
bcf_db.debug(endpoint='project_put',
request={'project_id': project_id, 'project_request': project_request},
response=project_response.dict())
bcf_db.debug(
endpoint="project_put",
request={"project_id": project_id, "project_request": project_request},
response=project_response.dict(),
)
return project_response
@router.get("/bcf/3.0/projects/{project_id}/extensions", tags=["project_extensions_get"])
def project_extensions_get(project_id: UUID,
current_user: User = Depends(get_current_active_user)) -> ExtensionsGET:
def project_extensions_get(project_id: UUID, current_user: User = Depends(get_current_active_user)) -> ExtensionsGET:
extensions_response = bcf_db.get_project_extensions(project_id, current_user)
bcf_db.debug(endpoint='project_extensions_get',
request={'project_id': project_id},
response=extensions_response.dict())
bcf_db.debug(
endpoint="project_extensions_get", request={"project_id": project_id}, response=extensions_response.dict()
)
return extensions_response
@@ -86,62 +88,68 @@ def project_extensions_get(project_id: UUID,
#
# Topics
@router.get("/bcf/3.0/projects/{project_id}/topics", tags=["topics_get"])
def topics_get(project_id: str,
current_user: User = Depends(get_current_active_user)) -> List[TopicGET]:
def topics_get(project_id: str, current_user: User = Depends(get_current_active_user)) -> List[TopicGET]:
topics_response = bcf_db.get_topics(project_id, current_user)
bcf_db.debug(endpoint='topics_get',
request={'project_id': project_id},
response={count: value.dict() for count, value in enumerate(topics_response)})
bcf_db.debug(
endpoint="topics_get",
request={"project_id": project_id},
response={count: value.dict() for count, value in enumerate(topics_response)},
)
return topics_response
@router.post("/bcf/3.0/projects/{project_id}/topics", tags=["topic_post"], status_code=201)
def topic_post(project_id: UUID, topic_request: TopicPOST,
current_user: User = Depends(get_current_active_user)) -> TopicGET:
def topic_post(
project_id: UUID, topic_request: TopicPOST, current_user: User = Depends(get_current_active_user)
) -> TopicGET:
topic_response = bcf_db.post_topic(project_id, topic_request, current_user)
if topic_response is None:
raise HTTPException(status_code=400, detail="Could not create topic.")
bcf_db.debug(endpoint='topic_post',
request={'project_id': project_id, 'topic_request': topic_request.dict()},
response=topic_response.dict())
bcf_db.debug(
endpoint="topic_post",
request={"project_id": project_id, "topic_request": topic_request.dict()},
response=topic_response.dict(),
)
return topic_response
# Implemented
@router.get("/bcf/3.0/projects/{project_id}/topics/{topic_id}", tags=["topic_get"])
def topic_get(project_id: UUID, topic_id: UUID,
current_user: User = Depends(get_current_active_user)) -> TopicGET:
def topic_get(project_id: UUID, topic_id: UUID, current_user: User = Depends(get_current_active_user)) -> TopicGET:
topic_response = bcf_db.get_topic(project_id, topic_id, current_user)
if topic_response is None:
raise HTTPException(status_code=404, detail="Item not found.")
bcf_db.debug(endpoint='topic_get',
request={'project_id': project_id, 'topic_id': topic_id},
response=topic_response.dict())
bcf_db.debug(
endpoint="topic_get", request={"project_id": project_id, "topic_id": topic_id}, response=topic_response.dict()
)
return topic_response
# Implemented
@router.put("/bcf/3.0/projects/{project_id}/topics/{topic_id}", tags=["topic_put"], status_code=200)
def topic_put(project_id: UUID, topic_id: UUID, topic_request: TopicPUT,
current_user: User = Depends(get_current_active_user)) -> TopicGET:
def topic_put(
project_id: UUID, topic_id: UUID, topic_request: TopicPUT, current_user: User = Depends(get_current_active_user)
) -> TopicGET:
topic_response = bcf_db.put_topic(project_id, topic_id, topic_request, current_user)
bcf_db.debug(endpoint='topic_put',
request={'project_id': project_id, 'topic_id': topic_id, 'topic_request': topic_request.dict()},
response=topic_response.dict())
bcf_db.debug(
endpoint="topic_put",
request={"project_id": project_id, "topic_id": topic_id, "topic_request": topic_request.dict()},
response=topic_response.dict(),
)
return topic_response
# Implemented
@router.delete("/bcf/3.0/projects/{project_id}/topics/{topic_id}", tags=["topic_delete"], status_code=200)
def topic_delete(project_id: UUID, topic_id: UUID,
current_user: User = Depends(get_current_active_user)) -> int:
def topic_delete(project_id: UUID, topic_id: UUID, current_user: User = Depends(get_current_active_user)) -> int:
topic_response = bcf_db.delete_topic(project_id, topic_id, current_user)
if topic_response is None:
raise HTTPException(status_code=404, detail="Item not found.")
bcf_db.debug(endpoint='topic_delete',
request={'project_id': project_id, 'topic_id': topic_id},
response={topic_response})
bcf_db.debug(
endpoint="topic_delete", request={"project_id": project_id, "topic_id": topic_id}, response={topic_response}
)
return topic_response
@@ -153,25 +161,31 @@ def topic_delete(project_id: UUID, topic_id: UUID,
# Implemented
@router.get("/bcf/3.0/projects/{project_id}/topics/{topic_id}/snippet", tags=["bim_snippet_get"])
def bim_snippet_get(project_id: UUID, topic_id: UUID,
current_user: User = Depends(get_current_active_user)) -> BimSnippet:
def bim_snippet_get(
project_id: UUID, topic_id: UUID, current_user: User = Depends(get_current_active_user)
) -> BimSnippet:
bim_snippet_response = bcf_db.get_bim_snippet(project_id, topic_id, current_user)
if bim_snippet_response is None:
raise HTTPException(status_code=404, detail="Item not found.")
bcf_db.debug(endpoint='bim_snippet_get',
request={'project_id': project_id, 'topic_id': topic_id},
response=bim_snippet_response.dict())
bcf_db.debug(
endpoint="bim_snippet_get",
request={"project_id": project_id, "topic_id": topic_id},
response=bim_snippet_response.dict(),
)
return bim_snippet_response
# Implemented
@router.put("/bcf/3.0/projects/{project_id}/topics/{topic_id}/snippet", tags=["bim_snippet_put"], status_code=200)
def bim_snippet_put(project_id: UUID, topic_id: UUID, snippet: BimSnippet,
current_user: User = Depends(get_current_active_user)) -> BimSnippet:
def bim_snippet_put(
project_id: UUID, topic_id: UUID, snippet: BimSnippet, current_user: User = Depends(get_current_active_user)
) -> BimSnippet:
bim_snippet_response = bcf_db.put_bim_snippet(project_id, topic_id, snippet, current_user)
bcf_db.debug(endpoint='bim_snippet_put',
request={'project_id': project_id, 'topic_id': topic_id, 'snippet': snippet.dict()},
response=bim_snippet_response.dict())
bcf_db.debug(
endpoint="bim_snippet_put",
request={"project_id": project_id, "topic_id": topic_id, "snippet": snippet.dict()},
response=bim_snippet_response.dict(),
)
return bim_snippet_response
@@ -182,36 +196,45 @@ def bim_snippet_put(project_id: UUID, topic_id: UUID, snippet: BimSnippet,
@router.get("/bcf/3.0/projects/{project_id}/files_information", tags=["files_information_get"])
def files_information_get(project_id: UUID,
current_user: User = Depends(get_current_active_user)) -> List[ProjectFileInformation]:
def files_information_get(
project_id: UUID, current_user: User = Depends(get_current_active_user)
) -> List[ProjectFileInformation]:
files_information_response = bcf_db.get_files_information(project_id, current_user)
bcf_db.debug(endpoint='files_information_get',
request={'project_id': project_id},
response={count: value.dict() for count, value in enumerate(files_information_response)})
bcf_db.debug(
endpoint="files_information_get",
request={"project_id": project_id},
response={count: value.dict() for count, value in enumerate(files_information_response)},
)
return files_information_response
# Implemented
@router.get("/bcf/3.0/projects/{project_id}/topics/{topic_id}/files", tags=["files_get"])
def files_get(project_id: UUID, topic_id: UUID,
current_user: User = Depends(get_current_active_user)) -> List[FileGET]:
def files_get(project_id: UUID, topic_id: UUID, current_user: User = Depends(get_current_active_user)) -> List[FileGET]:
files_response = bcf_db.get_files(project_id, topic_id, current_user)
bcf_db.debug(endpoint='files_get',
request={'project_id': project_id, 'topic_id': topic_id},
response={count: value.dict() for count, value in enumerate(files_response)})
bcf_db.debug(
endpoint="files_get",
request={"project_id": project_id, "topic_id": topic_id},
response={count: value.dict() for count, value in enumerate(files_response)},
)
return files_response
# request body file = FilePUT
@router.put("/bcf/3.0/projects/{project_id}/topics/{topic_id}/files", tags=["files_put"], status_code=200)
def files_put(project_id: UUID, topic_id: UUID, files: List[FilePUT],
current_user: User = Depends(get_current_active_user)) -> List[FileGET]:
def files_put(
project_id: UUID, topic_id: UUID, files: List[FilePUT], current_user: User = Depends(get_current_active_user)
) -> List[FileGET]:
files_response = bcf_db.put_files(project_id, topic_id, files, current_user)
bcf_db.debug(endpoint='files_put',
request={'project_id': project_id,
'topic_id': topic_id,
'files': {count: value.dict() for count, value in enumerate(files)}},
response={count: value.dict() for count, value in enumerate(files_response)})
bcf_db.debug(
endpoint="files_put",
request={
"project_id": project_id,
"topic_id": topic_id,
"files": {count: value.dict() for count, value in enumerate(files)},
},
response={count: value.dict() for count, value in enumerate(files_response)},
)
return files_response
@@ -222,58 +245,80 @@ def files_put(project_id: UUID, topic_id: UUID, files: List[FilePUT],
@router.get("/bcf/3.0/projects/{project_id}/topics/{topic_id}/comments", tags=["comments_get"])
def comments_get(project_id: UUID, topic_id: UUID,
current_user: User = Depends(get_current_active_user)) -> List[CommentGET]:
def comments_get(
project_id: UUID, topic_id: UUID, current_user: User = Depends(get_current_active_user)
) -> List[CommentGET]:
comments_response = bcf_db.get_comments(project_id, topic_id, current_user)
bcf_db.debug(endpoint='comments_get',
request={'project_id': project_id, 'topic_id': topic_id},
response={count: value.dict() for count, value in enumerate(comments_response)})
bcf_db.debug(
endpoint="comments_get",
request={"project_id": project_id, "topic_id": topic_id},
response={count: value.dict() for count, value in enumerate(comments_response)},
)
return comments_response
# request body comment = CommentPOST
@router.post("/bcf/3.0/projects/{project_id}/topics/{topic_id}/comments", tags=["comment_post"], status_code=201)
def comment_post(project_id: UUID, topic_id: UUID, comment: CommentPOST,
current_user: User = Depends(get_current_active_user)) -> CommentGET:
def comment_post(
project_id: UUID, topic_id: UUID, comment: CommentPOST, current_user: User = Depends(get_current_active_user)
) -> CommentGET:
comment_response = bcf_db.post_comment(project_id, topic_id, comment, current_user)
bcf_db.debug(endpoint='comment_post',
request={'project_id': project_id, 'topic_id': topic_id, 'comment': comment},
response=comment_response.dict())
bcf_db.debug(
endpoint="comment_post",
request={"project_id": project_id, "topic_id": topic_id, "comment": comment},
response=comment_response.dict(),
)
return comment_response
@router.get("/bcf/3.0/projects/{project_id}/topics/{topic_id}/comments/{comment_id}", tags=["comment_get"])
def comment_get(project_id: UUID, topic_id: UUID, comment_id: UUID,
current_user: User = Depends(get_current_active_user)) -> CommentGET:
def comment_get(
project_id: UUID, topic_id: UUID, comment_id: UUID, current_user: User = Depends(get_current_active_user)
) -> CommentGET:
comment_response = bcf_db.get_comment(project_id, topic_id, comment_id, current_user)
bcf_db.debug(endpoint='comment_get',
request={'project_id': project_id, 'topic_id': topic_id, 'comment_id': comment_id},
response=comment_response.dict())
bcf_db.debug(
endpoint="comment_get",
request={"project_id": project_id, "topic_id": topic_id, "comment_id": comment_id},
response=comment_response.dict(),
)
return comment_response
# request body comment = CommentPUT
@router.put("/bcf/3.0/projects/{project_id}/topics/{topic_id}/comments/{comment_id}", tags=["comment_put"], status_code=200)
def comment_put(project_id: UUID, topic_id: UUID, comment_id: UUID, comment: CommentPUT,
current_user: User = Depends(get_current_active_user)) -> CommentGET:
@router.put(
"/bcf/3.0/projects/{project_id}/topics/{topic_id}/comments/{comment_id}", tags=["comment_put"], status_code=200
)
def comment_put(
project_id: UUID,
topic_id: UUID,
comment_id: UUID,
comment: CommentPUT,
current_user: User = Depends(get_current_active_user),
) -> CommentGET:
comment_response = bcf_db.put_comment(project_id, topic_id, comment_id, comment, current_user)
bcf_db.debug(endpoint='comment_put',
request={'project_id': project_id, 'topic_id': topic_id, 'comment': comment},
response=comment_response.dict())
bcf_db.debug(
endpoint="comment_put",
request={"project_id": project_id, "topic_id": topic_id, "comment": comment},
response=comment_response.dict(),
)
return comment_response
# Implemented
@router.delete("/bcf/3.0/projects/{project_id}/topics/{topic_id}/comments/{comment_id}",
tags=["comment_delete"], status_code=200)
def comment_delete(project_id: UUID, topic_id: UUID, comment_id: UUID,
current_user: User = Depends(get_current_active_user)) -> int:
@router.delete(
"/bcf/3.0/projects/{project_id}/topics/{topic_id}/comments/{comment_id}", tags=["comment_delete"], status_code=200
)
def comment_delete(
project_id: UUID, topic_id: UUID, comment_id: UUID, current_user: User = Depends(get_current_active_user)
) -> int:
comment_response = bcf_db.delete_comment(project_id, topic_id, comment_id, current_user)
if comment_response is None:
raise HTTPException(status_code=404, detail="Item not found.")
bcf_db.debug(endpoint='comment_delete',
request={'project_id': project_id, 'topic_id': topic_id, 'comment_id': comment_id},
response={comment_response})
bcf_db.debug(
endpoint="comment_delete",
request={"project_id": project_id, "topic_id": topic_id, "comment_id": comment_id},
response={comment_response},
)
return comment_response
@@ -284,113 +329,160 @@ def comment_delete(project_id: UUID, topic_id: UUID, comment_id: UUID,
@router.get("/bcf/3.0/projects/{project_id}/topics/{topic_id}/viewpoints", tags=["viewpoints_get"])
def viewpoints_get(project_id: UUID, topic_id: UUID,
current_user: User = Depends(get_current_active_user)) -> List[ViewpointGET]:
def viewpoints_get(
project_id: UUID, topic_id: UUID, current_user: User = Depends(get_current_active_user)
) -> List[ViewpointGET]:
viewpoints_response = bcf_db.get_viewpoints(project_id, topic_id, current_user)
bcf_db.debug(endpoint='viewpoints_get',
request={'project_id': project_id, 'topic_id': topic_id},
response={count: value.dict() for count, value in enumerate(viewpoints_response)})
bcf_db.debug(
endpoint="viewpoints_get",
request={"project_id": project_id, "topic_id": topic_id},
response={count: value.dict() for count, value in enumerate(viewpoints_response)},
)
return viewpoints_response
# request body viewpoint = viewpointPOST
@router.post("/bcf/3.0/projects/{project_id}/topics/{topic_id}/viewpoints", tags=["viewpoint_post"], status_code=201)
def viewpoint_post(project_id: UUID, topic_id: UUID, viewpoint: ViewpointPOST,
current_user: User = Depends(get_current_active_user)) -> ViewpointGET:
def viewpoint_post(
project_id: UUID, topic_id: UUID, viewpoint: ViewpointPOST, current_user: User = Depends(get_current_active_user)
) -> ViewpointGET:
viewpoint_response = bcf_db.post_viewpoint(project_id, topic_id, viewpoint, current_user)
bcf_db.debug(endpoint='viewpoint_post',
request={'project_id': project_id, 'topic_id': topic_id, 'viewpoint': viewpoint.dict()},
response=viewpoint_response.dict())
bcf_db.debug(
endpoint="viewpoint_post",
request={"project_id": project_id, "topic_id": topic_id, "viewpoint": viewpoint.dict()},
response=viewpoint_response.dict(),
)
return viewpoint_response
@router.get("/bcf/3.0/projects/{project_id}/topics/{topic_id}/viewpoints/{viewpoint_id}", tags=["viewpoint_get"])
def viewpoint_get(project_id: UUID, topic_id: UUID, viewpoint_id: UUID,
current_user: User = Depends(get_current_active_user)) -> ViewpointGET:
def viewpoint_get(
project_id: UUID, topic_id: UUID, viewpoint_id: UUID, current_user: User = Depends(get_current_active_user)
) -> ViewpointGET:
viewpoint_response = bcf_db.get_viewpoint(project_id, topic_id, viewpoint_id, current_user)
bcf_db.debug(endpoint='viewpoint_get',
request={'project_id': project_id, 'topic_id': topic_id, 'viewpoint_id': viewpoint_id},
response=viewpoint_response.dict())
bcf_db.debug(
endpoint="viewpoint_get",
request={"project_id": project_id, "topic_id": topic_id, "viewpoint_id": viewpoint_id},
response=viewpoint_response.dict(),
)
return viewpoint_response
@router.get("/bcf/3.0/projects/{project_id}/topics/{topic_id}/viewpoints/{viewpoint_id}/snapshot",
tags=["viewpoint_snapshot_get"])
async def viewpoint_snapshot_get(project_id: UUID, topic_id: UUID, viewpoint_id: UUID,
current_user: User = Depends(get_current_active_user)) -> FileResponse:
@router.get(
"/bcf/3.0/projects/{project_id}/topics/{topic_id}/viewpoints/{viewpoint_id}/snapshot",
tags=["viewpoint_snapshot_get"],
)
async def viewpoint_snapshot_get(
project_id: UUID, topic_id: UUID, viewpoint_id: UUID, current_user: User = Depends(get_current_active_user)
) -> FileResponse:
viewpoint_snapshot_response = bcf_db.get_viewpoint_snapshot(project_id, topic_id, viewpoint_id, current_user)
bcf_db.debug(endpoint='viewpoint_snapshot_get',
request={'project_id': project_id, 'topic_id': topic_id, 'viewpoint_id': viewpoint_id},
response=viewpoint_snapshot_response)
snapshot_name = 'snapshot_' + str(viewpoint_id)
file_ending = '.' + viewpoint_snapshot_response.split('/', 2)[1]
snapshot_path = 'data/snapshots/' + snapshot_name + file_ending
bcf_db.debug(
endpoint="viewpoint_snapshot_get",
request={"project_id": project_id, "topic_id": topic_id, "viewpoint_id": viewpoint_id},
response=viewpoint_snapshot_response,
)
snapshot_name = "snapshot_" + str(viewpoint_id)
file_ending = "." + viewpoint_snapshot_response.split("/", 2)[1]
snapshot_path = "data/snapshots/" + snapshot_name + file_ending
snapshot_type = viewpoint_snapshot_response
return FileResponse(path=snapshot_path,
media_type=snapshot_type)
return FileResponse(path=snapshot_path, media_type=snapshot_type)
@router.get("/bcf/3.0/projects/{project_id}/topics/{topic_id}/viewpoints/{viewpoint_id}/bitmaps/{bitmap_id}",
tags=["viewpoint_bitmap_get"])
async def viewpoint_bitmap_get(project_id: UUID, topic_id: UUID, viewpoint_id: UUID, bitmap_id: UUID,
current_user: User = Depends(get_current_active_user)) -> FileResponse:
@router.get(
"/bcf/3.0/projects/{project_id}/topics/{topic_id}/viewpoints/{viewpoint_id}/bitmaps/{bitmap_id}",
tags=["viewpoint_bitmap_get"],
)
async def viewpoint_bitmap_get(
project_id: UUID,
topic_id: UUID,
viewpoint_id: UUID,
bitmap_id: UUID,
current_user: User = Depends(get_current_active_user),
) -> FileResponse:
viewpoint_bitmap_response = bcf_db.get_viewpoint_bitmap(project_id, topic_id, viewpoint_id, bitmap_id, current_user)
bcf_db.debug(endpoint='viewpoint_bitmap_get',
request={'project_id': project_id, 'topic_id': topic_id,
'viewpoint_id': viewpoint_id, 'bitmap_id': bitmap_id},
response=viewpoint_bitmap_response.dict())
bitmap_name = 'bitmap_' + str(viewpoint_id)
file_ending = '.' + viewpoint_bitmap_response['bitmap_type'].split('/', 2)[1]
bitmap_path = 'data/bitmaps/' + bitmap_name + file_ending
bitmap_type = viewpoint_bitmap_response['bitmap_type']
return FileResponse(path=bitmap_path,
media_type=bitmap_type)
bcf_db.debug(
endpoint="viewpoint_bitmap_get",
request={"project_id": project_id, "topic_id": topic_id, "viewpoint_id": viewpoint_id, "bitmap_id": bitmap_id},
response=viewpoint_bitmap_response.dict(),
)
bitmap_name = "bitmap_" + str(viewpoint_id)
file_ending = "." + viewpoint_bitmap_response["bitmap_type"].split("/", 2)[1]
bitmap_path = "data/bitmaps/" + bitmap_name + file_ending
bitmap_type = viewpoint_bitmap_response["bitmap_type"]
return FileResponse(path=bitmap_path, media_type=bitmap_type)
@router.get("/bcf/3.0/projects/{project_id}/topics/{topic_id}/viewpoints/{viewpoint_id}/coloring",
tags=["viewpoint_colored_components_get"])
def viewpoint_colored_components_get(project_id: UUID, topic_id: UUID, viewpoint_id: UUID,
current_user: User = Depends(get_current_active_user)) -> ColoringGET:
viewpoint_colored_components_response = bcf_db.get_viewpoint_colored_components(project_id, topic_id, viewpoint_id, current_user)
bcf_db.debug(endpoint='viewpoint_colored_components_get',
request={'project_id': project_id, 'topic_id': topic_id, 'viewpoint_id': viewpoint_id},
response=viewpoint_colored_components_response.dict())
@router.get(
"/bcf/3.0/projects/{project_id}/topics/{topic_id}/viewpoints/{viewpoint_id}/coloring",
tags=["viewpoint_colored_components_get"],
)
def viewpoint_colored_components_get(
project_id: UUID, topic_id: UUID, viewpoint_id: UUID, current_user: User = Depends(get_current_active_user)
) -> ColoringGET:
viewpoint_colored_components_response = bcf_db.get_viewpoint_colored_components(
project_id, topic_id, viewpoint_id, current_user
)
bcf_db.debug(
endpoint="viewpoint_colored_components_get",
request={"project_id": project_id, "topic_id": topic_id, "viewpoint_id": viewpoint_id},
response=viewpoint_colored_components_response.dict(),
)
return viewpoint_colored_components_response
@router.get("/bcf/3.0/projects/{project_id}/topics/{topic_id}/viewpoints/{viewpoint_id}/selection",
tags=["viewpoint_selected_components_get"])
def viewpoint_selected_components_get(project_id: UUID, topic_id: UUID, viewpoint_id: UUID,
current_user: User = Depends(get_current_active_user)) -> SelectionGET:
viewpoint_selected_components_response = bcf_db.get_viewpoint_selected_components(project_id, topic_id, viewpoint_id, current_user)
bcf_db.debug(endpoint='viewpoint_selected_components_get',
request={'project_id': project_id, 'topic_id': topic_id, 'viewpoint_id': viewpoint_id},
response=viewpoint_selected_components_response.dict())
@router.get(
"/bcf/3.0/projects/{project_id}/topics/{topic_id}/viewpoints/{viewpoint_id}/selection",
tags=["viewpoint_selected_components_get"],
)
def viewpoint_selected_components_get(
project_id: UUID, topic_id: UUID, viewpoint_id: UUID, current_user: User = Depends(get_current_active_user)
) -> SelectionGET:
viewpoint_selected_components_response = bcf_db.get_viewpoint_selected_components(
project_id, topic_id, viewpoint_id, current_user
)
bcf_db.debug(
endpoint="viewpoint_selected_components_get",
request={"project_id": project_id, "topic_id": topic_id, "viewpoint_id": viewpoint_id},
response=viewpoint_selected_components_response.dict(),
)
return viewpoint_selected_components_response
@router.get("/bcf/3.0/projects/{project_id}/topics/{topic_id}/viewpoints/{viewpoint_id}/visibility",
tags=["viewpoint_components_visibility_get"])
def viewpoint_components_visibility_get(project_id: UUID, topic_id: UUID, viewpoint_id: UUID,
current_user: User = Depends(get_current_active_user)) -> VisibilityGET:
viewpoint_components_visibility_response = bcf_db.get_viewpoint_components_visibility(project_id, topic_id, viewpoint_id, current_user)
bcf_db.debug(endpoint='viewpoint_components_visibility_get',
request={'project_id': project_id, 'topic_id': topic_id, 'viewpoint_id': viewpoint_id},
response=viewpoint_components_visibility_response.dict())
@router.get(
"/bcf/3.0/projects/{project_id}/topics/{topic_id}/viewpoints/{viewpoint_id}/visibility",
tags=["viewpoint_components_visibility_get"],
)
def viewpoint_components_visibility_get(
project_id: UUID, topic_id: UUID, viewpoint_id: UUID, current_user: User = Depends(get_current_active_user)
) -> VisibilityGET:
viewpoint_components_visibility_response = bcf_db.get_viewpoint_components_visibility(
project_id, topic_id, viewpoint_id, current_user
)
bcf_db.debug(
endpoint="viewpoint_components_visibility_get",
request={"project_id": project_id, "topic_id": topic_id, "viewpoint_id": viewpoint_id},
response=viewpoint_components_visibility_response.dict(),
)
return viewpoint_components_visibility_response
# Implemented
@router.delete("/bcf/3.0/projects/{project_id}/topics/{topic_id}/viewpoints/{viewpoint_id}",
tags=["viewpoint_delete"], status_code=200)
def viewpoint_delete(project_id: UUID, topic_id: UUID, viewpoint_id: UUID,
current_user: User = Depends(get_current_active_user)) -> int:
@router.delete(
"/bcf/3.0/projects/{project_id}/topics/{topic_id}/viewpoints/{viewpoint_id}",
tags=["viewpoint_delete"],
status_code=200,
)
def viewpoint_delete(
project_id: UUID, topic_id: UUID, viewpoint_id: UUID, current_user: User = Depends(get_current_active_user)
) -> int:
viewpoint_response = bcf_db.delete_viewpoint(project_id, topic_id, viewpoint_id, current_user)
if viewpoint_response is None:
raise HTTPException(status_code=404, detail="Item not found.")
bcf_db.debug(endpoint='viewpoint_delete',
request={'project_id': project_id, 'topic_id': topic_id, 'viewpoint_id': viewpoint_id},
response={viewpoint_response})
bcf_db.debug(
endpoint="viewpoint_delete",
request={"project_id": project_id, "topic_id": topic_id, "viewpoint_id": viewpoint_id},
response={viewpoint_response},
)
return viewpoint_response
@@ -401,24 +493,38 @@ def viewpoint_delete(project_id: UUID, topic_id: UUID, viewpoint_id: UUID,
@router.get("/bcf/3.0/projects/{project_id}/topics/{topic_id}/related_topics", tags=["related_topics_get"])
def related_topics_get(project_id: UUID, topic_id: UUID,
current_user: User = Depends(get_current_active_user)) -> List[RelatedTopicGET]:
def related_topics_get(
project_id: UUID, topic_id: UUID, current_user: User = Depends(get_current_active_user)
) -> List[RelatedTopicGET]:
related_topics_response = bcf_db.get_related_topics(project_id, topic_id, current_user)
bcf_db.debug(endpoint='related_topics_get',
request={'project_id': project_id, 'topic_id': topic_id},
response={count: value.dict() for count, value in enumerate(related_topics_response)})
bcf_db.debug(
endpoint="related_topics_get",
request={"project_id": project_id, "topic_id": topic_id},
response={count: value.dict() for count, value in enumerate(related_topics_response)},
)
return related_topics_response
# request body related_topic = RelatedTopicPUT
@router.put("/bcf/3.0/projects/{project_id}/topics/{topic_id}/related_topics", tags=["related_topics_put"], status_code=200)
def related_topics_put(project_id: UUID, topic_id: UUID, related_topics: List[RelatedTopicPUT],
current_user: User = Depends(get_current_active_user)) -> List[RelatedTopicGET]:
@router.put(
"/bcf/3.0/projects/{project_id}/topics/{topic_id}/related_topics", tags=["related_topics_put"], status_code=200
)
def related_topics_put(
project_id: UUID,
topic_id: UUID,
related_topics: List[RelatedTopicPUT],
current_user: User = Depends(get_current_active_user),
) -> List[RelatedTopicGET]:
related_topics_response = bcf_db.put_related_topics(project_id, topic_id, related_topics, current_user)
bcf_db.debug(endpoint='related_topics_put',
request={'project_id': project_id, 'topic_id': topic_id,
'related_topics': {count: value.dict() for count, value in enumerate(related_topics)}},
response={count: value.dict() for count, value in enumerate(related_topics_response)})
bcf_db.debug(
endpoint="related_topics_put",
request={
"project_id": project_id,
"topic_id": topic_id,
"related_topics": {count: value.dict() for count, value in enumerate(related_topics)},
},
response={count: value.dict() for count, value in enumerate(related_topics_response)},
)
return related_topics_response
@@ -428,51 +534,70 @@ def related_topics_put(project_id: UUID, topic_id: UUID, related_topics: List[Re
# Document references <- from topic
@router.get("/bcf/3.0/projects/{project_id}/topics/{topic_id}/document_references",
tags=["topic_document_references_get"])
def topic_document_references_get(project_id: UUID, topic_id: UUID,
current_user: User = Depends(get_current_active_user)) -> List[DocumentReferenceGET]:
@router.get(
"/bcf/3.0/projects/{project_id}/topics/{topic_id}/document_references", tags=["topic_document_references_get"]
)
def topic_document_references_get(
project_id: UUID, topic_id: UUID, current_user: User = Depends(get_current_active_user)
) -> List[DocumentReferenceGET]:
topic_document_references_response = bcf_db.get_topic_document_references(project_id, topic_id, current_user)
bcf_db.debug(endpoint='topic_document_references_get',
request={'project_id': project_id, 'topic_id': topic_id},
response={count: value.dict() for count, value in enumerate(topic_document_references_response)})
bcf_db.debug(
endpoint="topic_document_references_get",
request={"project_id": project_id, "topic_id": topic_id},
response={count: value.dict() for count, value in enumerate(topic_document_references_response)},
)
return topic_document_references_response
# request body document_reference = DocumentReferencePOST
@router.post("/bcf/3.0/projects/{project_id}/topics/{topic_id}/document_references",
tags=["topic_document_references_post"],
status_code=201)
def topic_document_reference_post(project_id: UUID, topic_id: UUID, document_reference: DocumentReferencePOST,
current_user: User = Depends(get_current_active_user)) -> DocumentReferenceGET:
topic_document_references_response = bcf_db.post_topic_document_references(project_id,
topic_id,
document_reference,
current_user)
bcf_db.debug(endpoint='topic_document_references_post',
request={'project_id': project_id, 'topic_id': topic_id, 'document_reference': document_reference},
response={count: value.dict() for count, value in enumerate(topic_document_references_response)})
@router.post(
"/bcf/3.0/projects/{project_id}/topics/{topic_id}/document_references",
tags=["topic_document_references_post"],
status_code=201,
)
def topic_document_reference_post(
project_id: UUID,
topic_id: UUID,
document_reference: DocumentReferencePOST,
current_user: User = Depends(get_current_active_user),
) -> DocumentReferenceGET:
topic_document_references_response = bcf_db.post_topic_document_references(
project_id, topic_id, document_reference, current_user
)
bcf_db.debug(
endpoint="topic_document_references_post",
request={"project_id": project_id, "topic_id": topic_id, "document_reference": document_reference},
response={count: value.dict() for count, value in enumerate(topic_document_references_response)},
)
return topic_document_references_response
# request body document_reference = DocumentReferencePUT
@router.put("/bcf/3.0/projects/{project_id}/topics/{topic_id}/document_references/{reference_id}",
tags=["topic_document_references_put"],
status_code=200)
def topic_document_references_put(project_id: UUID, topic_id: UUID, reference_id: UUID,
document_reference: DocumentReferencePUT,
current_user: User = Depends(get_current_active_user)) -> DocumentReferenceGET:
topic_document_references_response = bcf_db.put_topic_document_references(project_id,
topic_id,
reference_id,
document_reference,
current_user)
bcf_db.debug(endpoint='topic_document_references_put',
request={'project_id': project_id,
'topic_id': topic_id,
'reference_id': reference_id,
'document_reference': document_reference.dict()},
response={count: value.dict() for count, value in enumerate(topic_document_references_response)})
@router.put(
"/bcf/3.0/projects/{project_id}/topics/{topic_id}/document_references/{reference_id}",
tags=["topic_document_references_put"],
status_code=200,
)
def topic_document_references_put(
project_id: UUID,
topic_id: UUID,
reference_id: UUID,
document_reference: DocumentReferencePUT,
current_user: User = Depends(get_current_active_user),
) -> DocumentReferenceGET:
topic_document_references_response = bcf_db.put_topic_document_references(
project_id, topic_id, reference_id, document_reference, current_user
)
bcf_db.debug(
endpoint="topic_document_references_put",
request={
"project_id": project_id,
"topic_id": topic_id,
"reference_id": reference_id,
"document_reference": document_reference.dict(),
},
response={count: value.dict() for count, value in enumerate(topic_document_references_response)},
)
return topic_document_references_response
@@ -485,30 +610,34 @@ def topic_document_references_put(project_id: UUID, topic_id: UUID, reference_id
@router.get("/bcf/3.0/projects/{project_id}/documents", tags=["documents_get"])
def documents_get(project_id: UUID, current_user: User = Depends(get_current_active_user)) -> List[DocumentGET]:
documents_response = bcf_db.get_documents(project_id, current_user)
bcf_db.debug(endpoint='documents_get',
request={'project_id': project_id},
response={count: value.dict() for count, value in enumerate(documents_response)})
bcf_db.debug(
endpoint="documents_get",
request={"project_id": project_id},
response={count: value.dict() for count, value in enumerate(documents_response)},
)
return documents_response
# request body file = UploadFile
@router.post("/bcf/3.0/projects/{project_id}/documents", tags=["document_post"], status_code=201)
async def document_post(project_id: UUID, file: UploadFile,
current_user: User = Depends(get_current_active_user)) -> DocumentGET:
async def document_post(
project_id: UUID, file: UploadFile, current_user: User = Depends(get_current_active_user)
) -> DocumentGET:
document_response = bcf_db.post_document(project_id, file, current_user)
bcf_db.debug(endpoint='document_post',
request={'project_id': project_id},
response=document_response.dict())
bcf_db.debug(endpoint="document_post", request={"project_id": project_id}, response=document_response.dict())
return document_response
@router.get("/bcf/3.0/projects/{project_id}/documents/{document_id}", tags=["document_get"])
def document_get(project_id: UUID, document_id: UUID,
current_user: User = Depends(get_current_active_user)) -> DocumentGET:
def document_get(
project_id: UUID, document_id: UUID, current_user: User = Depends(get_current_active_user)
) -> DocumentGET:
document_response = bcf_db.get_document(project_id, document_id, current_user)
bcf_db.debug(endpoint='document_get',
request={'project_id': project_id, 'document_id': document_id},
response=document_response.dict())
bcf_db.debug(
endpoint="document_get",
request={"project_id": project_id, "document_id": document_id},
response=document_response.dict(),
)
return document_response
@@ -520,22 +649,26 @@ def document_get(project_id: UUID, document_id: UUID,
# ...
@router.get("/bcf/3.0/projects/{project_id}/topics/events", tags=["topics_events_get"])
def topics_events_get(project_id: UUID,
current_user: User = Depends(get_current_active_user)) -> List[TopicEventGET]:
def topics_events_get(project_id: UUID, current_user: User = Depends(get_current_active_user)) -> List[TopicEventGET]:
topic_events_response = bcf_db.get_topics_events(project_id, current_user)
bcf_db.debug(endpoint='topics_events_get',
request={'project_id': project_id},
response={count: value.dict() for count, value in enumerate(topic_events_response)})
bcf_db.debug(
endpoint="topics_events_get",
request={"project_id": project_id},
response={count: value.dict() for count, value in enumerate(topic_events_response)},
)
return topic_events_response
@router.get("/bcf/3.0/projects/{project_id}/topics/{topic_id}/events", tags=["topic_events_get"])
def topic_events_get(project_id: UUID, topic_id: UUID,
current_user: User = Depends(get_current_active_user)) -> List[TopicEventGET]:
def topic_events_get(
project_id: UUID, topic_id: UUID, current_user: User = Depends(get_current_active_user)
) -> List[TopicEventGET]:
topic_events_response = bcf_db.get_topic_events(project_id, topic_id, current_user)
bcf_db.debug(endpoint='topic_events_get',
request={'project_id': project_id, 'topic_id': topic_id},
response={count: value.dict() for count, value in enumerate(topic_events_response)})
bcf_db.debug(
endpoint="topic_events_get",
request={"project_id": project_id, "topic_id": topic_id},
response={count: value.dict() for count, value in enumerate(topic_events_response)},
)
return topic_events_response
@@ -546,21 +679,28 @@ def topic_events_get(project_id: UUID, topic_id: UUID,
@router.get("/bcf/3.0/projects/{project_id}/topics/comments/events", tags=["comments_events_get"])
def comments_events_get(project_id: UUID,
current_user: User = Depends(get_current_active_user)) -> List[CommentEventGET]:
def comments_events_get(
project_id: UUID, current_user: User = Depends(get_current_active_user)
) -> List[CommentEventGET]:
comments_events_response = bcf_db.get_comments_events(project_id, current_user)
bcf_db.debug(endpoint='comments_events_get',
request={'project_id': project_id},
response={count: value.dict() for count, value in enumerate(comments_events_response)})
bcf_db.debug(
endpoint="comments_events_get",
request={"project_id": project_id},
response={count: value.dict() for count, value in enumerate(comments_events_response)},
)
return comments_events_response
@router.get("/bcf/3.0/projects/{project_id}/topics/{topic_id}/comments/{comment_id}/events",
tags=["comment_events_get"])
def comment_events_get(project_id: UUID, topic_id: UUID, comment_id: UUID,
current_user: User = Depends(get_current_active_user)) -> List[CommentEventGET]:
@router.get(
"/bcf/3.0/projects/{project_id}/topics/{topic_id}/comments/{comment_id}/events", tags=["comment_events_get"]
)
def comment_events_get(
project_id: UUID, topic_id: UUID, comment_id: UUID, current_user: User = Depends(get_current_active_user)
) -> List[CommentEventGET]:
comment_events_response = bcf_db.get_comment_events(project_id, topic_id, comment_id, current_user)
bcf_db.debug(endpoint='comment_events_get',
request={'project_id': project_id, 'topic_id': topic_id, 'comment_id': comment_id},
response={count: value.dict() for count, value in enumerate(comment_events_response)})
bcf_db.debug(
endpoint="comment_events_get",
request={"project_id": project_id, "topic_id": topic_id, "comment_id": comment_id},
response={count: value.dict() for count, value in enumerate(comment_events_response)},
)
return comment_events_response
+192 -161
View File
@@ -1,4 +1,3 @@
import collections
import os
import shutil
@@ -6,7 +5,7 @@ import traceback
import sys
from fastapi import HTTPException, status, APIRouter, Request, Depends
from fastapi import UploadFile, Form
from fastapi import UploadFile, Form
from fastapi.responses import FileResponse, HTMLResponse
from fastapi.templating import Jinja2Templates
from fastapi.encoders import jsonable_encoder
@@ -87,12 +86,15 @@ templates = Jinja2Templates(directory="templates")
@router.post("/documents/1.0/upload-documents", tags=[""])
def upload_documents_post(upload_documents: UploadDocuments,
current_user: User = Depends(get_current_active_user)) -> DocumentUploadSessionInitialization:
def upload_documents_post(
upload_documents: UploadDocuments, current_user: User = Depends(get_current_active_user)
) -> DocumentUploadSessionInitialization:
post_upload_documents_response = doc_db.post_upload_documents(upload_documents, current_user)
doc_db.debug(endpoint='upload_documents_post',
request={'upload_documents': upload_documents},
response=post_upload_documents_response.dict())
doc_db.debug(
endpoint="upload_documents_post",
request={"upload_documents": upload_documents},
response=post_upload_documents_response.dict(),
)
return post_upload_documents_response
@@ -101,20 +103,23 @@ def upload_documents_post(upload_documents: UploadDocuments,
def upload_documents_get(request: Request, upload_session: UUID):
data_for_upload_documents = doc_db.get_data_for_upload_documents(upload_session)
print('Data for site: ', data_for_upload_documents)
print("Data for site: ", data_for_upload_documents)
return templates.TemplateResponse(
'upload_files.html',
{'request': request,
'upload_session': upload_session,
'username': data_for_upload_documents.current_user.username,
'email': data_for_upload_documents.current_user.email,
'full_name': data_for_upload_documents.current_user.full_name,
'server_context': data_for_upload_documents.server_context,
'callback_url': data_for_upload_documents.callback.url,
'callback_expires_in': data_for_upload_documents.callback.expires_in,
'documents': data_for_upload_documents.documents,
'projects': data_for_upload_documents.projects})
"upload_files.html",
{
"request": request,
"upload_session": upload_session,
"username": data_for_upload_documents.current_user.username,
"email": data_for_upload_documents.current_user.email,
"full_name": data_for_upload_documents.current_user.full_name,
"server_context": data_for_upload_documents.server_context,
"callback_url": data_for_upload_documents.callback.url,
"callback_expires_in": data_for_upload_documents.callback.expires_in,
"documents": data_for_upload_documents.documents,
"projects": data_for_upload_documents.projects,
},
)
@router.post("/documents/1.0/save-metadata-for-documents", tags=[""])
@@ -127,29 +132,29 @@ async def save_metadata_for_documents_post(request: Request) -> list:
print(form_data_json)
documents = collections.defaultdict(dict)
names = ('session_file_id', 'document', 'title', 'version_number', 'filename')
names = ("session_file_id", "document", "title", "version_number", "filename")
for whole_form_key, value in form_data_json.items():
if whole_form_key.startswith(names):
start_form_key, document_id = whole_form_key.split("@", 1)
print('New field: ', start_form_key, ' for document id: ', document_id)
print("New field: ", start_form_key, " for document id: ", document_id)
documents[document_id][start_form_key] = value
print("Documents: ")
print(documents)
username = form_data_json['username']
upload_session = form_data_json['upload_session']
server_context = form_data_json['server_context']
callback_url = form_data_json['callback_url']
callback_expires_in = form_data_json['callback_expires_in']
project = form_data_json['project']
username = form_data_json["username"]
upload_session = form_data_json["upload_session"]
server_context = form_data_json["server_context"]
callback_url = form_data_json["callback_url"]
callback_expires_in = form_data_json["callback_expires_in"]
project = form_data_json["project"]
documents_saved = list()
for key in documents:
try:
documents[key]['project'] = project
documents[key]["project"] = project
document = DocumentMetadata(**documents[key])
save_metadata_response = doc_db.save_metadata_for_documents(document, upload_session, username)
documents_saved.append(save_metadata_response)
@@ -157,9 +162,11 @@ async def save_metadata_for_documents_post(request: Request) -> list:
print(e)
continue
doc_db.debug(endpoint='save_metadata_for_documents_post',
request={'documents': documents},
response={'response': documents_saved})
doc_db.debug(
endpoint="save_metadata_for_documents_post",
request={"documents": documents},
response={"response": documents_saved},
)
return documents_saved
@@ -167,22 +174,30 @@ async def save_metadata_for_documents_post(request: Request) -> list:
# http://localhost:8080/cde-callback-example?upload_documents_url=
# https%3A%2F%2Fcde.example.com%2Fupload-instructions%3Fupload_session%3Dee56b8f3-8f93-4819-976e-46a45a5a996f
@router.post("/documents/1.0/upload-instructions", tags=[""])
def upload_instructions(session_id: str, server_context: str, upload_files: UploadFileDetails,
current_user: User = Depends(get_current_active_user)) -> DocumentsToUpload:
def upload_instructions(
session_id: str,
server_context: str,
upload_files: UploadFileDetails,
current_user: User = Depends(get_current_active_user),
) -> DocumentsToUpload:
documents_to_upload_model = DocumentsToUpload()
documents_to_upload_model.server_context = server_context
documents_to_upload_model.documents_to_upload = list()
for upload_file in upload_files.files:
get_upload_instructions_response = doc_db.get_upload_instructions(session_id, server_context, upload_file, current_user)
doc_db.debug(endpoint='upload_instructions',
request={'session_id': session_id,
'server_context': server_context,
'document': upload_file},
response=get_upload_instructions_response.dict())
get_upload_instructions_response = doc_db.get_upload_instructions(
session_id, server_context, upload_file, current_user
)
doc_db.debug(
endpoint="upload_instructions",
request={"session_id": session_id, "server_context": server_context, "document": upload_file},
response=get_upload_instructions_response.dict(),
)
documents_to_upload_model.documents_to_upload.append(get_upload_instructions_response)
return documents_to_upload_model
# ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ----
# summary: 'Upload a single file part'
#
@@ -206,8 +221,7 @@ def upload_instructions(session_id: str, server_context: str, upload_files: Uplo
@router.post("/documents/1.0/upload-part/{part_id}", tags=[""])
async def upload_part(part_id: str, request: Request,
current_user: User = Depends(get_current_active_user)):
async def upload_part(part_id: str, request: Request, current_user: User = Depends(get_current_active_user)):
# file_name = doc_db.safe_path(part_id)
file_name = part_id
@@ -222,33 +236,31 @@ async def upload_part(part_id: str, request: Request,
# try to receive the uploaded part
try:
print('File contents: ', request_body)
print("File contents: ", request_body)
# use document_id instead as dir_name
# dir_name = doc_db.safe_path(document.document_id)
dir_name = document.document_id
path = './data/document_parts/' + dir_name + '/'
path = "./data/document_parts/" + dir_name + "/"
if not os.path.exists(path):
os.makedirs(path)
with open(path + file_name, 'wb') as f:
with open(path + file_name, "wb") as f:
f.write(request_body)
except Exception:
print('Error uploading file')
print("Error uploading file")
print(traceback.format_exc())
print('Error uploading file')
print("Error uploading file")
print(sys.exc_info()[2])
finally:
# We will write to the database, information about part successfully uploaded.
doc_db.mark_part_as_uploaded(part_id, current_user)
doc_db.debug(endpoint='upload-part',
request={'part_id': part_id},
response={'uploaded': True})
doc_db.debug(endpoint="upload-part", request={"part_id": part_id}, response={"uploaded": True})
return {"message": f"Successfully uploaded part {file_name}"}
@@ -269,9 +281,11 @@ async def upload_part(part_id: str, request: Request,
# /server-provided-path-document-upload-cancellation
# description: This operation should be called to cancel the upload
@router.post("/documents/1.0/upload-completion", tags=[""])
def upload_completion(upload_session: str,
current_user: User = Depends(get_current_active_user)) -> Union[DocumentVersion, bool]:
def upload_completion(
upload_session: str, current_user: User = Depends(get_current_active_user)
) -> Union[DocumentVersion, bool]:
# check if all parts really are marked as uploaded in database
# retrieve document_id, file_type, file_ending, and parts_id (in order)
@@ -280,23 +294,23 @@ def upload_completion(upload_session: str,
raise HTTPException(status_code=400, detail="All parts not uploaded.")
parts = doc_db.retrieve_uploaded_parts(upload_session, current_user)
print('Number of parts: ' + str(len(parts)))
print("Number of parts: " + str(len(parts)))
document = doc_db.get_document_from_session(upload_session, current_user)
# check if all parts really are uploaded to document_id-dir
document_name = doc_db.safe_path(document.document_id)
path = './data/document_parts/' + document_name + '/'
path = "./data/document_parts/" + document_name + "/"
for part in parts:
part = doc_db.safe_path(part)
print('Checking for part ' + part + ' in dir ' + path)
print("Checking for part " + part + " in dir " + path)
if not os.path.isfile(path + part):
print(part + ' is not in dir ' + path)
print(part + " is not in dir " + path)
raise HTTPException(status_code=400, detail="All parts not in dir.")
else:
print(part + ' is in dir ' + path)
print(part + " is in dir " + path)
# merge parts to a new temporary document
temp_doc_path = path
@@ -304,14 +318,14 @@ def upload_completion(upload_session: str,
if not os.path.exists(temp_doc_path):
os.makedirs(temp_doc_path)
new_doc_path = './data/documents/'
new_doc_path = "./data/documents/"
new_doc_path_name = new_doc_path + document.file_description.name
# Read parts and write to temp doc.
with open(temp_doc_file_name, 'ab') as temp_doc:
with open(temp_doc_file_name, "ab") as temp_doc:
for part in parts:
part = doc_db.safe_path(part)
with open(temp_doc_path + part, 'rb') as part_doc:
with open(temp_doc_path + part, "rb") as part_doc:
temp_doc.write(part_doc.read())
# move document to new location in documents dir
@@ -329,13 +343,12 @@ def upload_completion(upload_session: str,
# get DocumentVersion
document = doc_db.get_document_version(document.document_id, document.version_index, current_user)
doc_db.debug(endpoint='upload_completion',
request={'upload_session': upload_session},
response=document.dict())
doc_db.debug(endpoint="upload_completion", request={"upload_session": upload_session}, response=document.dict())
return document
else:
return False
# ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ----
# summary: 'Cancel the upload of a single file'
#
@@ -355,14 +368,14 @@ def upload_cancellation(upload_session: str, current_user: User = Depends(get_cu
# clean temp dir
document_name = doc_db.safe_path(document.document_id)
path = './data/document_parts/' + document_name + '/'
path = "./data/document_parts/" + document_name + "/"
shutil.rmtree(path)
except Exception as e:
print(e)
finally:
print('Upload cancellation complete.')
print("Upload cancellation complete.")
return
@@ -399,17 +412,17 @@ def upload_cancellation(upload_session: str, current_user: User = Depends(get_cu
# that has been flagged to have a new version in the response.
#
@router.post("/documents/1.0/document-versions", tags=[""])
def document_versions_post(document_ids: List[UUID],
current_user: User = Depends(get_current_active_user)) -> List[DocumentVersion]:
def document_versions_post(
document_ids: List[UUID], current_user: User = Depends(get_current_active_user)
) -> List[DocumentVersion]:
document_versions = list()
for document_id in document_ids:
document_versions.append(doc_db.get_document_version(document_id, 1, current_user))
doc_db.debug(endpoint='document_versions_post',
request={document_ids},
response={document_versions})
doc_db.debug(endpoint="document_versions_post", request={document_ids}, response={document_versions})
return document_versions
@@ -460,12 +473,15 @@ def document_versions_post(document_ids: List[UUID],
@router.post("/documents/1.0/select-documents", tags=[""])
def select_documents_post(select_documents: SelectDocuments,
current_user: User = Depends(get_current_active_user)) -> DocumentDiscoverySessionInitialization:
def select_documents_post(
select_documents: SelectDocuments, current_user: User = Depends(get_current_active_user)
) -> DocumentDiscoverySessionInitialization:
post_select_documents_response = doc_db.post_select_documents(select_documents, current_user)
doc_db.debug(endpoint='select_documents_post',
request={'select_documents': select_documents},
response=post_select_documents_response.dict())
doc_db.debug(
endpoint="select_documents_post",
request={"select_documents": select_documents},
response=post_select_documents_response.dict(),
)
print("Returns ", post_select_documents_response)
return post_select_documents_response
@@ -490,19 +506,22 @@ def select_documents_post(select_documents: SelectDocuments,
# documents/1.0/document-selection?selection_session=7cf3dd70-c880-4fb1-9897-f60472959533
@router.get("/documents/1.0/document-selection", tags=[""], response_class=HTMLResponse)
def selected_documents_get(request: Request,
selection_session: UUID):
def selected_documents_get(request: Request, selection_session: UUID):
data_for_document_selection = doc_db.get_data_for_document_selection(selection_session)
return templates.TemplateResponse(
'select_files.html',
{'request': request,
'selection_session': selection_session,
'current_user': data_for_document_selection.current_user,
'server_context': data_for_document_selection.server_context,
'callback_url': data_for_document_selection.callback.url,
'callback_expires_in': data_for_document_selection.callback.expires_in,
'projects': data_for_document_selection.projects})
"select_files.html",
{
"request": request,
"selection_session": selection_session,
"current_user": data_for_document_selection.current_user,
"server_context": data_for_document_selection.server_context,
"callback_url": data_for_document_selection.callback.url,
"callback_expires_in": data_for_document_selection.callback.expires_in,
"projects": data_for_document_selection.projects,
},
)
@router.post("/documents/1.0/mark-documents-as-selected", tags=[""])
@@ -516,45 +535,52 @@ async def mark_documents_as_selected_post(request: Request) -> DocumentsMarkedAs
documents = list()
for key, value in form_data_json.items():
if 'document_' in key:
if "document_" in key:
document_id = key.split("ocument_", 1)[1]
documents.append(document_id)
print("Sends ", documents)
get_selected_response = doc_db.post_mark_documents_as_selected(documents, form_data_json['selection_session'])
doc_db.debug(endpoint='mark_some_documents_as_selected_post',
request={'documents': documents,
'form_data_json[selection_session]': form_data_json['selection_session']},
response=get_selected_response.dict())
get_selected_response = doc_db.post_mark_documents_as_selected(documents, form_data_json["selection_session"])
doc_db.debug(
endpoint="mark_some_documents_as_selected_post",
request={"documents": documents, "form_data_json[selection_session]": form_data_json["selection_session"]},
response=get_selected_response.dict(),
)
return get_selected_response
@router.get("/documents/1.0/download-instructions", tags=[""])
def download_instructions(session_id: UUID, server_context: str,
current_user: User = Depends(get_current_active_user)) -> SelectedDocuments:
def download_instructions(
session_id: UUID, server_context: str, current_user: User = Depends(get_current_active_user)
) -> SelectedDocuments:
get_download_instructions_response = doc_db.get_download_instructions(session_id, server_context, current_user)
doc_db.debug(endpoint='download_instructions',
request={'session_id': session_id,
'server_context': server_context},
response=get_download_instructions_response.dict())
doc_db.debug(
endpoint="download_instructions",
request={"session_id": session_id, "server_context": server_context},
response=get_download_instructions_response.dict(),
)
return get_download_instructions_response
# download links
@router.get("/documents/1.0/document/{document_id}/version/{version_index}", tags=[""])
def document_version(document_id: str, version_index: int,
current_user: User = Depends(get_current_active_user)) -> DocumentVersion:
def document_version(
document_id: str, version_index: int, current_user: User = Depends(get_current_active_user)
) -> DocumentVersion:
# This endpoint returns the document version model itself.
get_document_version = doc_db.get_document_version(document_id, version_index, current_user)
doc_db.debug(endpoint='document_version',
request={'document_id': document_id,
'version_index': version_index},
response=get_document_version.dict())
doc_db.debug(
endpoint="document_version",
request={"document_id": document_id, "version_index": version_index},
response=get_document_version.dict(),
)
return get_document_version
# ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ----
# summary: 'Get document metadata for a single document'
#
@@ -573,16 +599,21 @@ def document_version(document_id: str, version_index: int,
@router.get("/documents/1.0/document/{document_id}/version/{version_index}/metadata", tags=[""])
def document_version_metadata(document_id: str, version_index: int,
current_user: User = Depends(get_current_active_user)) -> DocumentMetadataEntries:
def document_version_metadata(
document_id: str, version_index: int, current_user: User = Depends(get_current_active_user)
) -> DocumentMetadataEntries:
# The metadata for document versions is a list of key-value pairs
get_document_version_metadata_result = doc_db.get_document_version_metadata(document_id, version_index, current_user)
doc_db.debug(endpoint='document_version',
request={'document_id': document_id,
'version_index': version_index},
response=get_document_version_metadata_result.dict())
get_document_version_metadata_result = doc_db.get_document_version_metadata(
document_id, version_index, current_user
)
doc_db.debug(
endpoint="document_version",
request={"document_id": document_id, "version_index": version_index},
response=get_document_version_metadata_result.dict(),
)
return get_document_version_metadata_result
# ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ----
# summary: 'Download the document'
#
@@ -601,47 +632,48 @@ def document_version_metadata(document_id: str, version_index: int,
@router.get("/documents/1.0/document/{document_id}/version/{version_index}/download", tags=[""])
def document_version_download(document_id: str, version_index: int,
current_user: User = Depends(get_current_active_user)) -> FileResponse:
def document_version_download(
document_id: str, version_index: int, current_user: User = Depends(get_current_active_user)
) -> FileResponse:
# The url to download the binary content of this document version.
# May either directly return the result or redirect to a storage provider
keep_characters = (' ', '.', '_', '-')
keep_characters = (" ", ".", "_", "-")
document_id = "".join(c for c in document_id if c.isalnum() or c in keep_characters).rstrip()
file_location = './data/documents/' + document_id + '.ifc'
return FileResponse(file_location,
media_type='application/x-step',
filename='6dbd4d52-14db-11ee-be56-0242ac120002.ifc')
file_location = "./data/documents/" + document_id + ".ifc"
return FileResponse(
file_location, media_type="application/x-step", filename="6dbd4d52-14db-11ee-be56-0242ac120002.ifc"
)
@router.get("/documents/1.0/document/{document_id}/version/{version_index}/versions", tags=[""])
def document_versions(document_id: str, version_index: int,
current_user: User = Depends(get_current_active_user)) -> DocumentVersions:
def document_versions(
document_id: str, version_index: int, current_user: User = Depends(get_current_active_user)
) -> DocumentVersions:
# This url returns a list of all document versions for the parent document.
# The client can use this URL to monitor for new document versions
get_document_versions_result = doc_db.get_document_versions(document_id, current_user)
doc_db.debug(endpoint='document_version',
request={'document_id': document_id},
response=get_document_versions_result.dict())
doc_db.debug(
endpoint="document_version", request={"document_id": document_id}, response=get_document_versions_result.dict()
)
return get_document_versions_result
@router.get("/documents/1.0/document/{document_id}/version/{version_index}/details", tags=[""],
response_class=HTMLResponse)
def document_version_details(request: Request,
document_id: str,
version_index: int,
current_user: User = Depends(get_current_active_user)):
@router.get(
"/documents/1.0/document/{document_id}/version/{version_index}/details", tags=[""], response_class=HTMLResponse
)
def document_version_details(
request: Request, document_id: str, version_index: int, current_user: User = Depends(get_current_active_user)
):
# This url returns a list of all document versions for the parent document.
# The client can use this URL to monitor for new document versions
details = doc_db.get_document_version(document_id, version_index, current_user)
doc_db.debug(endpoint='document_version',
request={'document_id': document_id,
'version_index': version_index},
response=details.dict())
return templates.TemplateResponse(
'document_details.html',
{'request': request,
'details': details})
doc_db.debug(
endpoint="document_version",
request={"document_id": document_id, "version_index": version_index},
response=details.dict(),
)
return templates.TemplateResponse("document_details.html", {"request": request, "details": details})
# ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ----
# summary: 'Get the versions of a single document'
@@ -699,7 +731,9 @@ def document_version_details(request: Request,
@router.post("/documents/1.0/upload_file_to_project", tags=[""])
async def upload_documents_post(file: UploadFile, project: str = Form(...), selection_session: str = Form(...)) -> Document:
async def upload_documents_post(
file: UploadFile, project: str = Form(...), selection_session: str = Form(...)
) -> Document:
# Get the file size (in bytes)
file.file.seek(0, 2)
@@ -713,49 +747,46 @@ async def upload_documents_post(file: UploadFile, project: str = Form(...), sele
# Find file name ending and create new storage file name
if file.filename.lower().endswith(tuple(file_types)):
file_ending = file.filename.split('.')[-1].lower()
name = document_id + '.' + file_ending
file_ending = file.filename.split(".")[-1].lower()
name = document_id + "." + file_ending
else:
file_ending = ''
file_ending = ""
name = document_id
# Get mime type and file type
mime_type = ''
file_type = ''
mime_type = ""
file_type = ""
if hasattr(file_types, file_ending):
mime_type = file_types[file_ending]['mime_type']
file_type = file_types[file_ending]['file_type']
mime_type = file_types[file_ending]["mime_type"]
file_type = file_types[file_ending]["file_type"]
# Create document data
document_version_dict = {
'document_id': document_id,
'session_file_id': '',
'version_index': 1,
'version_number': '1',
'creation_date': doc_db.timestamp(),
'title': file.filename,
'original_file_name': file.filename,
'file_ending': file_ending,
'mime_type': mime_type,
'file_type': file_type,
'project': project,
'file_description': {
'name': name,
'size_in_bytes': file_size
}
"document_id": document_id,
"session_file_id": "",
"version_index": 1,
"version_number": "1",
"creation_date": doc_db.timestamp(),
"title": file.filename,
"original_file_name": file.filename,
"file_ending": file_ending,
"mime_type": mime_type,
"file_type": file_type,
"project": project,
"file_description": {"name": name, "size_in_bytes": file_size},
}
document_version_model = Document(**document_version_dict)
# Save file to disc
upload_directory = './data/documents/'
upload_directory = "./data/documents/"
destination_path = os.path.join(upload_directory, name)
with open(destination_path, 'wb') as buffer:
with open(destination_path, "wb") as buffer:
shutil.copyfileobj(file.file, buffer)
# create database record
inserted_document = doc_db.create_node_for_uploaded_file(selection_session, project, document_version_model)
print('Created node for document id: ' + str(inserted_document.document_id))
print("Created node for document id: " + str(inserted_document.document_id))
doc_db.create_ifc_graph_for_document(inserted_document.document_id)
# return document version of database record
+81 -77
View File
@@ -28,11 +28,10 @@ authorization_code = None
templates = Jinja2Templates(directory="templates")
clients = {
os.environ['KONTROLL_CLIENT_ID']:
{
'name': os.environ['KONTROLL_CLIENT_NAME'],
'secret': secrets['kontroll_client_secret']
}
os.environ["KONTROLL_CLIENT_ID"]: {
"name": os.environ["KONTROLL_CLIENT_NAME"],
"secret": secrets["kontroll_client_secret"],
}
}
# ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ----
@@ -60,21 +59,25 @@ clients = {
@router.get("/foundation/versions", tags=["api_versions_get"])
def api_versions_get():
return {
"versions": [{
"api_id": "foundation",
"version_id": "1.0",
"detailed_version": "https://github.com/BuildingSMART/foundation-API/tree/release_1_0"
}, {
"api_id": "bcf",
"version_id": "3.0",
"detailed_version": "https://github.com/buildingSMART/BCF-API/tree/release_3_0",
"api_base_url": os.environ['KONTROLL_BASE_URL'] + "bcf/3.0"
}, {
"api_id": "documents",
"version_id": "1.0",
"detailed_version": "https://github.com/buildingSMART/documents-API/tree/release_1_0",
"api_base_url": os.environ['KONTROLL_BASE_URL'] + "documents/1.0"
}]
"versions": [
{
"api_id": "foundation",
"version_id": "1.0",
"detailed_version": "https://github.com/BuildingSMART/foundation-API/tree/release_1_0",
},
{
"api_id": "bcf",
"version_id": "3.0",
"detailed_version": "https://github.com/buildingSMART/BCF-API/tree/release_3_0",
"api_base_url": os.environ["KONTROLL_BASE_URL"] + "bcf/3.0",
},
{
"api_id": "documents",
"version_id": "1.0",
"detailed_version": "https://github.com/buildingSMART/documents-API/tree/release_1_0",
"api_base_url": os.environ["KONTROLL_BASE_URL"] + "documents/1.0",
},
]
}
@@ -95,18 +98,15 @@ def api_versions_get():
# is not supported by the server.
@router.get("/foundation/1.0/auth",
tags=["foundation_auth_get"])
@router.get("/foundation/1.0/auth", tags=["foundation_auth_get"])
def authentication_get():
return_variable = {
"oauth2_auth_url": os.environ['KONTROLL_BASE_URL'] + "foundation/oauth2/auth",
"oauth2_token_url": os.environ['KONTROLL_BASE_URL'] + "foundation/oauth2/token",
"oauth2_auth_url": os.environ["KONTROLL_BASE_URL"] + "foundation/oauth2/auth",
"oauth2_token_url": os.environ["KONTROLL_BASE_URL"] + "foundation/oauth2/token",
# "oauth2_dynamic_client_reg_url": os.environ['KONTROLL_BASE_URL'] + "foundation/oauth2/reg",
"http_basic_supported": True,
"supported_oauth2_flows": [
"authorization_code_grant"
]
"supported_oauth2_flows": ["authorization_code_grant"],
}
print(return_variable)
return return_variable
@@ -135,23 +135,25 @@ def authentication_get():
@router.get("/foundation/oauth2/auth", response_class=HTMLResponse)
def authorization(request: Request,
response_type: str,
client_id: str,
state: str,
scope: str,
redirect_uri: str,
):
def authorization(
request: Request,
response_type: str,
client_id: str,
state: str,
scope: str,
redirect_uri: str,
):
client_name = clients[client_id]['name']
client_name = clients[client_id]["name"]
print(f"Response type: {response_type}, "
f"Client_id: {client_id}, "
f"Client_name: {client_name}, "
f"State: {state}, "
f"Scope: {scope},"
f"Redirect_URI: {redirect_uri}."
)
print(
f"Response type: {response_type}, "
f"Client_id: {client_id}, "
f"Client_name: {client_name}, "
f"State: {state}, "
f"Scope: {scope},"
f"Redirect_URI: {redirect_uri}."
)
# 3. Solibri sends the user to oauth2_auth_url with the following parameters:
# response_type=code, client_id=solibri_test_001, state=..., redirect_uri=uri, scope=...
@@ -159,38 +161,41 @@ def authorization(request: Request,
return templates.TemplateResponse(
"login.html",
{"request": request,
"response_type": response_type,
"client_id": client_id,
"client_name": client_name,
"state": state,
"scope": scope,
"redirect_uri": redirect_uri,
})
{
"request": request,
"response_type": response_type,
"client_id": client_id,
"client_name": client_name,
"state": state,
"scope": scope,
"redirect_uri": redirect_uri,
},
)
@router.get("/foundation/oauth2/code")
def code(username: str,
password: str,
response_type: str,
client_id,
client_name,
state: str,
redirect_uri: str,
scope: str = ''
):
def code(
username: str,
password: str,
response_type: str,
client_id,
client_name,
state: str,
redirect_uri: str,
scope: str = "",
):
global oauth2_state
oauth2_state = state
print('Username: ' + username + '. Password: ' + password)
print("Username: " + username + ". Password: " + password)
user = authenticate_user(username, password)
if not user:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Incorrect username or password",
headers={"WWW-Authenticate": "Bearer"}
headers={"WWW-Authenticate": "Bearer"},
)
# The user is signed in, now the main purpose of this function is to generate the authorization code.
@@ -242,36 +247,35 @@ def code(username: str,
# POST https://example.com/foundation/oauth2/token?grant_type=authorization_code&code=<your_authorization_code>
@router.post("/foundation/oauth2/token",
tags=["login_for_access_token_post"],
status_code=201)
@router.post("/foundation/oauth2/token", tags=["login_for_access_token_post"], status_code=201)
def login_for_access_token(
grant_type: Optional[str] = Form(None),
refresh_token: Optional[str] = Form(None),
code: Optional[str] = Form(None),
credentials: HTTPBasicCredentials = Depends(http_basic)):
grant_type: Optional[str] = Form(None),
refresh_token: Optional[str] = Form(None),
code: Optional[str] = Form(None),
credentials: HTTPBasicCredentials = Depends(http_basic),
):
print('grant_type: ', grant_type)
print('refresh_token: ', refresh_token)
print('code: ', code)
print('credentials: ', credentials)
print("grant_type: ", grant_type)
print("refresh_token: ", refresh_token)
print("code: ", code)
print("credentials: ", credentials)
# The API should check that the credentials (client_id and client_secret) are correct
# credentials.username contains the client_id
# credentials.password contains the client_secret
if credentials.username not in clients or credentials.password != clients[credentials.username]['secret']:
if credentials.username not in clients or credentials.password != clients[credentials.username]["secret"]:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Incorrect client_id or client_secret",
)
if grant_type == 'authorization_code':
if grant_type == "authorization_code":
# use authorization code,
# create access token and refresh token,
# delete authorization code
user_info = foundation_db.use_authorization_code(code)
elif grant_type == 'refresh_token':
elif grant_type == "refresh_token":
# use refresh token to get access token
# delete old access token and old refresh token
# create new access token and a new refresh token
@@ -279,8 +283,8 @@ def login_for_access_token(
user_info = foundation_db.use_refresh_token(refresh_token)
user_info.token_type = "Bearer"
user_info.expires_in = int(os.environ['SECURITY_ACCESS_TOKEN_EXPIRE_SECONDS'])
print('user_info: ', user_info)
user_info.expires_in = int(os.environ["SECURITY_ACCESS_TOKEN_EXPIRE_SECONDS"])
print("user_info: ", user_info)
return user_info
+13 -8
View File
@@ -9,8 +9,8 @@ import httpx
def log_info(req_body, res_body, route_url):
logging.info('request:' + route_url + ':' + str(req_body))
logging.info('response:' + route_url + ':' + str(res_body))
logging.info("request:" + route_url + ":" + str(req_body))
logging.info("response:" + route_url + ":" + str(res_body))
class LoggingRoute(APIRoute):
@@ -22,21 +22,26 @@ class LoggingRoute(APIRoute):
response = await original_route_handler(request)
route_url = str(request.url)
if isinstance(response, StreamingResponse):
res_body = b''
res_body = b""
async for item in response.body_iterator:
res_body += item
task = BackgroundTask(log_info, req_body, res_body, route_url)
return Response(content=res_body, status_code=response.status_code,
headers=dict(response.headers), media_type=response.media_type, background=task)
return Response(
content=res_body,
status_code=response.status_code,
headers=dict(response.headers),
media_type=response.media_type,
background=task,
)
else:
if hasattr(response, 'body'):
if hasattr(response, "body"):
res_body = response.body
else:
res_body = {'no response': True}
res_body = {"no response": True}
response.background = BackgroundTask(log_info, req_body, res_body, route_url)
return response
return custom_route_handler
logging.basicConfig(filename='logs/info.log', level=logging.DEBUG)
logging.basicConfig(filename="logs/info.log", level=logging.DEBUG)
+54 -48
View File
@@ -1,10 +1,9 @@
import collections
import os
import traceback
import sys
from fastapi import APIRouter, Request, Depends
from fastapi import APIRouter, Request, Depends
from fastapi.responses import FileResponse, HTMLResponse
from fastapi.templating import Jinja2Templates
from fastapi.encoders import jsonable_encoder
@@ -30,13 +29,17 @@ templates = Jinja2Templates(directory="templates")
# UPLOAD FLOW
################################################################
@router.post("/user/1.0/upload-documents", tags=[""])
def upload_documents_post(upload_documents: UploadDocuments,
current_user: User = Depends(get_current_active_user)) -> DocumentUploadSessionInitialization:
def upload_documents_post(
upload_documents: UploadDocuments, current_user: User = Depends(get_current_active_user)
) -> DocumentUploadSessionInitialization:
post_upload_documents_response = doc_db.post_upload_documents(upload_documents, current_user)
doc_db.debug(endpoint='upload_documents_post',
request={'upload_documents': upload_documents},
response=post_upload_documents_response.dict())
doc_db.debug(
endpoint="upload_documents_post",
request={"upload_documents": upload_documents},
response=post_upload_documents_response.dict(),
)
return post_upload_documents_response
@@ -45,20 +48,23 @@ def upload_documents_post(upload_documents: UploadDocuments,
def upload_documents_get(request: Request, upload_session: UUID):
data_for_upload_documents = doc_db.get_data_for_upload_documents(upload_session)
print('Data for site: ', data_for_upload_documents)
print("Data for site: ", data_for_upload_documents)
return templates.TemplateResponse(
'upload_files.html',
{'request': request,
'upload_session': upload_session,
'username': data_for_upload_documents.current_user.username,
'email': data_for_upload_documents.current_user.email,
'full_name': data_for_upload_documents.current_user.full_name,
'server_context': data_for_upload_documents.server_context,
'callback_url': data_for_upload_documents.callback.url,
'callback_expires_in': data_for_upload_documents.callback.expires_in,
'documents': data_for_upload_documents.documents,
'projects': data_for_upload_documents.projects})
"upload_files.html",
{
"request": request,
"upload_session": upload_session,
"username": data_for_upload_documents.current_user.username,
"email": data_for_upload_documents.current_user.email,
"full_name": data_for_upload_documents.current_user.full_name,
"server_context": data_for_upload_documents.server_context,
"callback_url": data_for_upload_documents.callback.url,
"callback_expires_in": data_for_upload_documents.callback.expires_in,
"documents": data_for_upload_documents.documents,
"projects": data_for_upload_documents.projects,
},
)
@router.post("/user/1.0/save-metadata-for-documents", tags=[""])
@@ -71,29 +77,29 @@ async def save_metadata_for_documents_post(request: Request) -> list:
print(form_data_json)
documents = collections.defaultdict(dict)
names = ('session_file_id', 'document', 'title', 'version_number', 'filename')
names = ("session_file_id", "document", "title", "version_number", "filename")
for whole_form_key, value in form_data_json.items():
if whole_form_key.startswith(names):
start_form_key, document_id = whole_form_key.split("@", 1)
print('New field: ', start_form_key, ' for document id: ', document_id)
print("New field: ", start_form_key, " for document id: ", document_id)
documents[document_id][start_form_key] = value
print("Documents: ")
print(documents)
username = form_data_json['username']
upload_session = form_data_json['upload_session']
server_context = form_data_json['server_context']
callback_url = form_data_json['callback_url']
callback_expires_in = form_data_json['callback_expires_in']
project = form_data_json['project']
username = form_data_json["username"]
upload_session = form_data_json["upload_session"]
server_context = form_data_json["server_context"]
callback_url = form_data_json["callback_url"]
callback_expires_in = form_data_json["callback_expires_in"]
project = form_data_json["project"]
documents_saved = list()
for key in documents:
try:
documents[key]['project'] = project
documents[key]["project"] = project
document = DocumentMetadata(**documents[key])
save_metadata_response = doc_db.save_metadata_for_documents(document, upload_session, username)
documents_saved.append(save_metadata_response)
@@ -101,9 +107,11 @@ async def save_metadata_for_documents_post(request: Request) -> list:
print(e)
continue
doc_db.debug(endpoint='save_metadata_for_documents_post',
request={'documents': documents},
response={'response': documents_saved})
doc_db.debug(
endpoint="save_metadata_for_documents_post",
request={"documents": documents},
response={"response": documents_saved},
)
return documents_saved
@@ -113,8 +121,7 @@ async def save_metadata_for_documents_post(request: Request) -> list:
@router.post("/user/1.0/upload-part/{part_id}", tags=[""])
async def upload_part(part_id: str, request: Request,
current_user: User = Depends(get_current_active_user)):
async def upload_part(part_id: str, request: Request, current_user: User = Depends(get_current_active_user)):
# file_name = doc_db.safe_path(part_id)
file_name = part_id
@@ -129,33 +136,31 @@ async def upload_part(part_id: str, request: Request,
# try to receive the uploaded part
try:
print('File contents: ', request_body)
print("File contents: ", request_body)
# use document_id instead as dir_name
# dir_name = doc_db.safe_path(document.document_id)
dir_name = document.document_id
path = './data/document_parts/' + dir_name + '/'
path = "./data/document_parts/" + dir_name + "/"
if not os.path.exists(path):
os.makedirs(path)
with open(path + file_name, 'wb') as f:
with open(path + file_name, "wb") as f:
f.write(request_body)
except Exception:
print('Error uploading file')
print("Error uploading file")
print(traceback.format_exc())
print('Error uploading file')
print("Error uploading file")
print(sys.exc_info()[2])
finally:
# We will write to the database, information about part successfully uploaded.
doc_db.mark_part_as_uploaded(part_id, current_user)
doc_db.debug(endpoint='upload-part',
request={'part_id': part_id},
response={'uploaded': True})
doc_db.debug(endpoint="upload-part", request={"part_id": part_id}, response={"uploaded": True})
return {"message": f"Successfully uploaded part {file_name}"}
@@ -166,13 +171,14 @@ async def upload_part(part_id: str, request: Request,
@router.get("/user/1.0/document/{document_id}/version/{version_index}/download", tags=[""])
def document_version_download(document_id: str, version_index: int,
current_user: User = Depends(get_current_active_user)) -> FileResponse:
def document_version_download(
document_id: str, version_index: int, current_user: User = Depends(get_current_active_user)
) -> FileResponse:
# The url to download the binary content of this document version.
# May either directly return the result or redirect to a storage provider
keep_characters = (' ', '.', '_', '-')
keep_characters = (" ", ".", "_", "-")
document_id = "".join(c for c in document_id if c.isalnum() or c in keep_characters).rstrip()
file_location = './data/documents/' + document_id + '.ifc'
return FileResponse(file_location,
media_type='application/x-step',
filename='6dbd4d52-14db-11ee-be56-0242ac120002.ifc')
file_location = "./data/documents/" + document_id + ".ifc"
return FileResponse(
file_location, media_type="application/x-step", filename="6dbd4d52-14db-11ee-be56-0242ac120002.ifc"
)
+20 -12
View File
@@ -18,9 +18,9 @@ get_secrets()
# otherwise the environment variable will have a value of neo4j://kontroll_neo4j:27687
# kontroll_neo4j is the docker-compose network.
driver = GraphDatabase.driver(os.environ['NEO4J_URI'],
auth=(os.environ['NEO4J_USER'],
os.environ['NEO4J_INITIAL_PASSWORD']))
driver = GraphDatabase.driver(
os.environ["NEO4J_URI"], auth=(os.environ["NEO4J_USER"], os.environ["NEO4J_INITIAL_PASSWORD"])
)
# initial password should be changed to secret password
@@ -33,33 +33,38 @@ class MyDB:
def __init__(self, object_driver):
self.driver = object_driver
self.database = 'neo4j'
self.database = "neo4j"
@staticmethod
def timestamp():
return datetime.now(timezone.utc).isoformat(sep='T', timespec='milliseconds')
return datetime.now(timezone.utc).isoformat(sep="T", timespec="milliseconds")
@staticmethod
def bcf_time(any_datetime):
if isinstance(any_datetime, type('str')):
if isinstance(any_datetime, type("str")):
datetime_any = parser.parse(any_datetime).astimezone(pytz.utc)
elif isinstance(any_datetime, type(datetime.now())):
datetime_any = any_datetime.astimezone(pytz.utc)
else:
return False
string_date = datetime_any.isoformat(sep='T', timespec='milliseconds')
string_date = datetime_any.isoformat(sep="T", timespec="milliseconds")
return str(string_date)
@staticmethod
def safe_path(path_name):
safe_path_name = ''.join(x for x in path_name if x.isalnum() or '-')
safe_path_name = "".join(x for x in path_name if x.isalnum() or "-")
return safe_path_name
@staticmethod
def debug(endpoint: str, request, response):
print("\n\n\nEndpoint: ", jsonpickle.dumps(endpoint),
"\nRequest: ", jsonpickle.dumps(request),
"\nResponse: ", jsonpickle.dumps(response))
print(
"\n\n\nEndpoint: ",
jsonpickle.dumps(endpoint),
"\nRequest: ",
jsonpickle.dumps(request),
"\nResponse: ",
jsonpickle.dumps(response),
)
@staticmethod
def node_to_json(node):
@@ -89,11 +94,12 @@ class MyDB:
cypher_file = open(cypher_file_path, "r")
cypher_data = cypher_file.read()
cypher_file.close()
cypher_statements = cypher_data.split(';')
cypher_statements = cypher_data.split(";")
cypher_statements.pop()
for cypher_statement in cypher_statements:
tx.run(cypher_statement)
return
with self.driver.session() as session:
return session.execute_write(initialize_db_work)
@@ -113,8 +119,10 @@ class MyDB:
user_dict = self.node_to_json(user_node)
user = UserInDB(**user_dict)
return user
with self.driver.session() as session:
return session.execute_read(get_user_work, username_work=username)
db = MyDB(driver)
db.initialize_db()
+11 -11
View File
@@ -28,24 +28,24 @@ from py2neo import Graph
def create_pure_node_from_ifc_entity(ifc_entity, ifc_file, hierarchy=True):
node = Node()
if ifc_entity.id() != 0:
node['id'] = ifc_entity.id()
node["id"] = ifc_entity.id()
else:
node['id'] = str(uuid4())
node['name'] = ifc_entity.is_a()
node["id"] = str(uuid4())
node["name"] = ifc_entity.is_a()
if hierarchy:
for label in ifc_file.wrapped_data.types_with_super():
if ifc_entity.is_a(label):
node.add_label(label)
else:
node.add_label(ifc_entity.is_a())
attributes_type = ['ENTITY INSTANCE', 'AGGREGATE OF ENTITY INSTANCE', 'DERIVED']
attributes_type = ["ENTITY INSTANCE", "AGGREGATE OF ENTITY INSTANCE", "DERIVED"]
for i in range(ifc_entity.__len__()):
if not ifc_entity.wrapped_data.get_argument_type(i) in attributes_type:
name = ifc_entity.wrapped_data.get_argument_name(i)
name_value = ifc_entity.wrapped_data.get_argument(i)
node[name]= name_value
node.__primarylabel__ = 'Root'
node.__primarykey__ = 'id'
node[name] = name_value
node.__primarylabel__ = "Root"
node.__primarykey__ = "id"
return node
@@ -55,14 +55,14 @@ def create_graph_from_ifc_entity_all(graph, ifc_entity, ifc_file):
graph.merge(node)
for i in range(ifc_entity.__len__()):
if ifc_entity[i]:
if ifc_entity.wrapped_data.get_argument_type(i) == 'ENTITY INSTANCE':
if ifc_entity[i].is_a() in ['IfcOwnerHistory'] and ifc_entity.is_a() != 'IfcProject':
if ifc_entity.wrapped_data.get_argument_type(i) == "ENTITY INSTANCE":
if ifc_entity[i].is_a() in ["IfcOwnerHistory"] and ifc_entity.is_a() != "IfcProject":
continue
else:
sub_node = create_pure_node_from_ifc_entity(ifc_entity[i], ifc_file)
REL = Relationship(node, ifc_entity.wrapped_data.get_argument_name(i), sub_node)
graph.merge(REL)
elif ifc_entity.wrapped_data.get_argument_type(i) == 'AGGREGATE OF ENTITY INSTANCE':
elif ifc_entity.wrapped_data.get_argument_type(i) == "AGGREGATE OF ENTITY INSTANCE":
for sub_entity in ifc_entity[i]:
sub_node = create_pure_node_from_ifc_entity(sub_entity, ifc_file)
REL = Relationship(node, ifc_entity.wrapped_data.get_argument_name(i), sub_node)
@@ -83,7 +83,7 @@ def create_full_graph(graph, ifc_file):
length = len(ifc_file.wrapped_data.entity_names())
for entity_id in ifc_file.wrapped_data.entity_names():
entity = ifc_file.by_id(entity_id)
print(idx, '/', length, entity)
print(idx, "/", length, entity)
create_graph_from_ifc_entity_all(graph, entity, ifc_file)
idx += 1
return
+89 -60
View File
@@ -13,79 +13,110 @@ endpoint_metadata = [
{"name": "authentication_get", "description": "/authentication"},
{"name": "login_for_access_token_post", "description": "/foundation/oauth2/token"},
{"name": "current_user_get", "description": "/foundation/1.0/current-user"},
{"name": "projects_get",
"description": "Retrieve a collection of projects that the currently logged on user has access to."},
{"name": "project_get",
"description": "Retrieve a specific project. The top level data container is known as the BCF project, "
"with a UUID and a project name attribute."},
{"name": "project_put",
"description": "Modify a specific project. This operation is only possible when the server returns the update "
"flag in the Project authorization."},
{"name": "project_extensions_get",
"description": "Retrieve a specific projects extensions. Project extensions are used to define possible values "
"that can be used in topics and comments, for example topic labels and priorities. They may "
"change during the course of a project. The most recent extensions state which values are valid "
"at a given moment for newly created topics and comments."},
{"name": "topics_get",
"description": "Retrieve a collection of topics related to a project (default sort order is creation_date)."},
{"name": "topic_post",
"description": "Add a new topic. The BCF project contains zero or more topics. Each topic represents a model "
"issue. A topic will have a UUID, a title, description, priority, stage, labels (similar to "
"tags), creation date / author, due date, and assigned to. If modified, it may contain the "
"modification date and author."},
{
"name": "projects_get",
"description": "Retrieve a collection of projects that the currently logged on user has access to.",
},
{
"name": "project_get",
"description": "Retrieve a specific project. The top level data container is known as the BCF project, "
"with a UUID and a project name attribute.",
},
{
"name": "project_put",
"description": "Modify a specific project. This operation is only possible when the server returns the update "
"flag in the Project authorization.",
},
{
"name": "project_extensions_get",
"description": "Retrieve a specific projects extensions. Project extensions are used to define possible values "
"that can be used in topics and comments, for example topic labels and priorities. They may "
"change during the course of a project. The most recent extensions state which values are valid "
"at a given moment for newly created topics and comments.",
},
{
"name": "topics_get",
"description": "Retrieve a collection of topics related to a project (default sort order is creation_date).",
},
{
"name": "topic_post",
"description": "Add a new topic. The BCF project contains zero or more topics. Each topic represents a model "
"issue. A topic will have a UUID, a title, description, priority, stage, labels (similar to "
"tags), creation date / author, due date, and assigned to. If modified, it may contain the "
"modification date and author.",
},
{"name": "topic_get", "description": "Retrieve a specific topic."},
{"name": "topic_put", "description": "Modify a specific topic, description similar to POST."},
{"name": "bim_snippet_get",
"description": "Retrieves a topics BIM-Snippet as binary file. BIM snippet has been in BCF specification since "
"the very beginning, but is has never been used. Snippets have originally been added to provide "
"for 'changes in IFC'. To get this really working in a CDE environment changes to the IFC format "
"is necessary."},
{"name": "bim_snippet_put",
"description": "Puts a new BIM Snippet binary file to a topic. If this is used, the parent topics BIM Snippet "
"property is_external must be set to false and the reference must be the file name with "
"extension."},
{
"name": "bim_snippet_get",
"description": "Retrieves a topics BIM-Snippet as binary file. BIM snippet has been in BCF specification since "
"the very beginning, but is has never been used. Snippets have originally been added to provide "
"for 'changes in IFC'. To get this really working in a CDE environment changes to the IFC format "
"is necessary.",
},
{
"name": "bim_snippet_put",
"description": "Puts a new BIM Snippet binary file to a topic. If this is used, the parent topics BIM Snippet "
"property is_external must be set to false and the reference must be the file name with "
"extension.",
},
{"name": "files_get", "description": "Retrieve a collection of file references as topic header."},
{"name": "files_put", "description": "Update a collection of file references on the topic header."},
{"name": "comments_get",
"description": "Retrieve a collection of all comments related to a topic (default ordering is date)."},
{
"name": "comments_get",
"description": "Retrieve a collection of all comments related to a topic (default ordering is date).",
},
{"name": "comment_post", "description": "Add a new comment to a topic."},
{"name": "comment_put", "description": "Update a single comment, description similar to POST."},
{"name": "comment_get", "description": "Get a single comment."},
{"name": "viewpoints_get", "description": "Retrieve a collection of all viewpoints related to a topic."},
{"name": "viewpoint_post",
"description": "Add a new viewpoint. Viewpoints are immutable, meaning that they should never change. "
"Requirements for different visualizations should be handled by creating new viewpoint elements."},
{
"name": "viewpoint_post",
"description": "Add a new viewpoint. Viewpoints are immutable, meaning that they should never change. "
"Requirements for different visualizations should be handled by creating new viewpoint elements.",
},
{"name": "viewpoint_get", "description": "Retrieve a specific viewpoint."},
{"name": "viewpoint_selected_components_get",
"description": "Retrieve a collection of all selected components in a viewpoint."},
{"name": "viewpoint_colored_components_get",
"description": "Retrieve a collection of all colored components in a viewpoint."},
{
"name": "viewpoint_selected_components_get",
"description": "Retrieve a collection of all selected components in a viewpoint.",
},
{
"name": "viewpoint_colored_components_get",
"description": "Retrieve a collection of all colored components in a viewpoint.",
},
{"name": "viewpoint_components_visibility_get", "description": "Retrieve visibility of components in a viewpoint."},
{"name": "viewpoint_snapshot_get", "description": "Retrieve a specific viewpoints bitmap image file (png or jpg)."},
{"name": "related_topics_get", "description": "Retrieve a collection of all related topics to a topic."},
{"name": "related_topics_put", "description": "Add or update a collection of all related topics to a topic."},
{"name": "topic_document_references_get",
"description": "Retrieve a collection of all document references to a topic."},
{
"name": "topic_document_references_get",
"description": "Retrieve a collection of all document references to a topic.",
},
{"name": "topic_document_references_post", "description": "Add or update document references to a topic."},
{"name": "topic_document_references_put", "description": "Add or update document references to a topic."},
{"name": "documents_get", "description": "Retrieve a collection of all documents uploaded to a project."},
{"name": "document_post", "description": "Upload a document (binary file) to a project."},
{"name": "document_get", "description": "Retrieves a document as binary file."},
{"name": "topics_events_get",
"description": "Retrieve a collection of topic events related to a project (default sort order is date)."},
{"name": "topic_events_get",
"description": "Retrieve a collection of topic events related to a project (default sort order is date)."},
{"name": "comments_events_get",
"description": "Retrieve a collection of comment events related to a project (default sort order is date)."},
{"name": "comment_events_get",
"description": "Retrieve a collection of comment events related to a comment (default sort order is date)."}
{
"name": "topics_events_get",
"description": "Retrieve a collection of topic events related to a project (default sort order is date).",
},
{
"name": "topic_events_get",
"description": "Retrieve a collection of topic events related to a project (default sort order is date).",
},
{
"name": "comments_events_get",
"description": "Retrieve a collection of comment events related to a project (default sort order is date).",
},
{
"name": "comment_events_get",
"description": "Retrieve a collection of comment events related to a comment (default sort order is date).",
},
]
app = FastAPI(
title="Kontroll API",
description="Implementering av BCF API 3.0",
version="0.0.1",
openapi_tags=endpoint_metadata
title="Kontroll API", description="Implementering av BCF API 3.0", version="0.0.1", openapi_tags=endpoint_metadata
)
# Configure app to accept requests from anywhere
@@ -98,23 +129,21 @@ app.add_middleware(
allow_headers=["*"],
)
app.include_router(foundation.router, prefix='')
app.include_router(bcf.router, prefix='')
app.include_router(documents.router, prefix='')
app.include_router(foundation.router, prefix="")
app.include_router(bcf.router, prefix="")
app.include_router(documents.router, prefix="")
templates = Jinja2Templates(directory="templates")
@app.get("/", response_class=HTMLResponse)
def index(request: Request):
return templates.TemplateResponse(
"index.html",
{"request": request})
return templates.TemplateResponse("index.html", {"request": request})
favicon_path = 'favicon.ico'
favicon_path = "favicon.ico"
@app.get('/favicon.ico', include_in_schema=False)
@app.get("/favicon.ico", include_in_schema=False)
async def favicon():
return FileResponse(favicon_path)
@@ -55,13 +55,13 @@ class ClippingPlane(BaseModel):
class SnapshotType(Enum):
jpg = 'jpg'
png = 'png'
jpg = "jpg"
png = "png"
class BitmapType(Enum):
jpg = 'jpg'
png = 'png'
jpg = "jpg"
png = "png"
class Component(BaseModel):
@@ -2,9 +2,9 @@ from models.bcf_common import *
class ProjectAction(Enum):
update = 'update'
createTopic = 'createTopic'
createDocument = 'createDocument'
update = "update"
createTopic = "createTopic"
createDocument = "createDocument"
class ProjectGETAuthorization(BaseModel):
@@ -18,19 +18,19 @@ class ProjectGET(BaseModel):
class TopicAction(Enum):
update = 'update'
updateBimSnippet = 'updateBimSnippet'
updateRelatedTopics = 'updateRelatedTopics'
updateDocumentReferences = 'updateDocumentReferences'
updateFiles = 'updateFiles'
createComment = 'createComment'
createViewpoint = 'createViewpoint'
delete = 'delete'
update = "update"
updateBimSnippet = "updateBimSnippet"
updateRelatedTopics = "updateRelatedTopics"
updateDocumentReferences = "updateDocumentReferences"
updateFiles = "updateFiles"
createComment = "createComment"
createViewpoint = "createViewpoint"
delete = "delete"
class CommentAction(Enum):
update = 'update'
delete = 'delete'
update = "update"
delete = "delete"
class ExtensionsGET(BaseModel):
@@ -123,7 +123,7 @@ class SnapshotGET(BaseModel):
class ViewpointAction(Enum):
delete = 'delete'
delete = "delete"
class ViewpointGETAuthorization(BaseModel):
@@ -174,6 +174,8 @@ class TopicEventGET(BaseModel):
topic_guid: str
date: str
author: str
# actions: Optional[List[EventAction]] = Field(None, min_items=1)
@@ -182,6 +184,8 @@ class CommentEventGET(BaseModel):
topic_guid: str
date: str
author: str
# actions: Optional[List[EventAction]] = Field(None, min_items=1)
@@ -10,12 +10,10 @@ from typing import List, Optional
class CallbackLink(BaseModel):
url: constr(min_length=1) = Field(
description='The server will web-browser-redirect to this URL once the user has completed selecting '
'documents or entering document metadata on the CDE'
)
expires_in: int = Field(
description='The expiry period for the URL, in seconds'
description="The server will web-browser-redirect to this URL once the user has completed selecting "
"documents or entering document metadata on the CDE"
)
expires_in: int = Field(description="The expiry period for the URL, in seconds")
# ---- RESPONSE MODELS ---- #
@@ -35,62 +33,52 @@ class DocumentVersionLinks(BaseModel):
class FileDescription(BaseModel):
name: constr(min_length=1) = Field(
description='The name of the document version file on the server. The files are named by '
'document_id.file_ending',
example='908e1cd4-2e09-11ee-be56-0242ac120002.ifc'
)
size_in_bytes: int = Field(
description='The size of the file in bytes',
example='124563'
description="The name of the document version file on the server. The files are named by "
"document_id.file_ending",
example="908e1cd4-2e09-11ee-be56-0242ac120002.ifc",
)
size_in_bytes: int = Field(description="The size of the file in bytes", example="124563")
class Document(BaseModel):
document_id: constr(min_length=1) = Field(
description='A machine readable identifier that can be used to uniquely identify this version in future calls '
'UUID is used - see `Query` section',
example='908e1cd4-2e09-11ee-be56-0242ac120002'
description="A machine readable identifier that can be used to uniquely identify this version in future calls "
"UUID is used - see `Query` section",
example="908e1cd4-2e09-11ee-be56-0242ac120002",
)
session_file_id: Optional[str] = Field(
description='A machine readable identifier that can be used to uniquely the file '
'during the upload session, UUID is used',
example='908e1cd4-2e09-11ee-be56-0242ac120002'
description="A machine readable identifier that can be used to uniquely the file "
"during the upload session, UUID is used",
example="908e1cd4-2e09-11ee-be56-0242ac120002",
)
version_index: int = Field(
description='A machine readable sequence number of the version of the document. The sequence must be ordered, '
'so that newer versions have higher values than previous ones. Each version index must be unique '
'for that document, but there may be gaps in the sequence',
example='12'
description="A machine readable sequence number of the version of the document. The sequence must be ordered, "
"so that newer versions have higher values than previous ones. Each version index must be unique "
"for that document, but there may be gaps in the sequence",
example="12",
)
version_number: Optional[constr(min_length=1)] = Field(
description='A human readable version number. This is not expected to be in any specific format across CDEs '
'and may hold any value',
example='V2.0-larger'
description="A human readable version number. This is not expected to be in any specific format across CDEs "
"and may hold any value",
example="V2.0-larger",
)
creation_date: str = Field(
description='The creation date of the document revision',
example='2016-04-28T16:31:12.270+02:00'
description="The creation date of the document revision", example="2016-04-28T16:31:12.270+02:00"
)
title: Optional[constr(min_length=1)] = Field(
description='A human readable code or identifier. Metadata entered by user in CDE.',
example='Large garage'
description="A human readable code or identifier. Metadata entered by user in CDE.", example="Large garage"
)
original_file_name: Optional[str] = Field(
description='The full name of the file as sent to the API',
example='First_floor_vent.ifc')
file_ending: Optional[str] = Field(
description='The ending of the file name, including the dot',
example='.ifc')
mime_type: Optional[str] = Field(
description='The mime type identifier',
example='application/x-step')
file_type: Optional[str] = Field(
description='The full name of the file type',
example='STEP Physical File (SPF)')
description="The full name of the file as sent to the API", example="First_floor_vent.ifc"
)
file_ending: Optional[str] = Field(description="The ending of the file name, including the dot", example=".ifc")
mime_type: Optional[str] = Field(description="The mime type identifier", example="application/x-step")
file_type: Optional[str] = Field(description="The full name of the file type", example="STEP Physical File (SPF)")
project: Optional[str] = Field(
description='The project to which the document will belong once it has been uploaded,'
'this information is added as metadata by the user in the CDE',
example='908e1cd4-2e09-11ee-be56-0242ac120003')
description="The project to which the document will belong once it has been uploaded,"
"this information is added as metadata by the user in the CDE",
example="908e1cd4-2e09-11ee-be56-0242ac120003",
)
file_description: FileDescription
parts: Optional[List[str]]
@@ -21,8 +21,8 @@ class ProjectOnly(BaseModel):
class DataForUploadDocuments(BaseModel):
server_context: Optional[str] = Field(
description="A CDE controlled identifier recording the user's context on the CDE. For example which project "
'and folder the user was on. If the client provides the `server_context` in subsequent calls then '
'the CDE will attemp to load the UI at the same place.'
"and folder the user was on. If the client provides the `server_context` in subsequent calls then "
"the CDE will attemp to load the UI at the same place."
)
documents: List[FileToUpload]
callback: Optional[CallbackLink]
@@ -32,25 +32,24 @@ class DataForUploadDocuments(BaseModel):
# ---- DOWNLOAD MODELS ----
class DocumentMetadataEntries(BaseModel):
metadata: List[DocumentMetadataEntry] = Field(
description='An array of metadata entries'
)
metadata: List[DocumentMetadataEntry] = Field(description="An array of metadata entries")
class Project(BaseModel):
project_id: str
name: str
documents: Optional[List[Document]] = Field(
description='An array containing all the documents selected by the user'
description="An array containing all the documents selected by the user"
)
class DataForDocumentSelection(BaseModel):
server_context: Optional[str] = Field(
description="A CDE controlled identifier recording the user's context on the CDE. For example which project "
'and folder the user was on. If the client provides the `server_context` in subsequent calls then '
'the CDE will attemp to load the UI at the same place.'
"and folder the user was on. If the client provides the `server_context` in subsequent calls then "
"the CDE will attemp to load the UI at the same place."
)
projects: List[Project]
callback: Optional[CallbackLink]
@@ -61,24 +60,8 @@ class DataForDocumentSelection(BaseModel):
file_types = {
'smc': {
'file_type': 'Solibri Model Checker',
'file_ending': '.smc',
'mime_type': 'application/octet-stream'
},
'ifc': {
'file_type': 'STEP Physical File',
'file_ending': '.ifc',
'mime_type': 'application/x-step'
},
'ifczip': {
'file_type': 'ZIP of a STEP Physical File',
'file_ending': '.ifcZIP',
'mime_type': 'application/zip'
},
'pdf': {
'file_type': 'Adobe Portable Document Format',
'file_ending': '.pdf',
'mime_type': 'application/pdf'
}
"smc": {"file_type": "Solibri Model Checker", "file_ending": ".smc", "mime_type": "application/octet-stream"},
"ifc": {"file_type": "STEP Physical File", "file_ending": ".ifc", "mime_type": "application/x-step"},
"ifczip": {"file_type": "ZIP of a STEP Physical File", "file_ending": ".ifcZIP", "mime_type": "application/zip"},
"pdf": {"file_type": "Adobe Portable Document Format", "file_ending": ".pdf", "mime_type": "application/pdf"},
}
@@ -13,15 +13,15 @@ from models.documents_common import CallbackLink
class FileToUpload(BaseModel):
file_name: constr(min_length=1) = Field(
description='The CDE UI will display this value to the User when entering document metadata. This is the '
'original name of the file. This attribute is the same as the name attribute in a document model.'
description="The CDE UI will display this value to the User when entering document metadata. This is the "
"original name of the file. This attribute is the same as the name attribute in a document model."
)
session_file_id: constr(min_length=1) = Field(
description='This is a client provided id to differentiate between multiple files that are being uploaded in '
'the same session'
description="This is a client provided id to differentiate between multiple files that are being uploaded in "
"the same session"
)
document_id: Optional[constr(min_length=1)] = Field(
description='When present, indicates that this upload is a new version of an existing document'
description="When present, indicates that this upload is a new version of an existing document"
)
@@ -29,19 +29,17 @@ class UploadDocuments(BaseModel):
callback: CallbackLink
server_context: Optional[str] = Field(
description="A CDE controlled identifier recording the user's context on the CDE. For example which project "
'and folder the user was on. If the client provides the `server_context` in subsequent calls then '
'the CDE will attemp to load the UI at the same place.'
"and folder the user was on. If the client provides the `server_context` in subsequent calls then "
"the CDE will attemp to load the UI at the same place."
)
files: List[FileToUpload]
class UploadFileDetail(BaseModel):
size_in_bytes: int = Field(
description='The uploaded file size'
)
size_in_bytes: int = Field(description="The uploaded file size")
session_file_id: constr(min_length=1) = Field(
description='This is a client provided id to differentiate between multiple files that are being uploaded in '
'the same session'
description="This is a client provided id to differentiate between multiple files that are being uploaded in "
"the same session"
)
@@ -56,37 +54,31 @@ class SelectDocuments(BaseModel):
callback: CallbackLink
server_context: Optional[str] = Field(
description="A CDE controlled identifier recording the user's context on the CDE. For example which project "
'and folder the user was on. If the client provides the `server_context` in subsequent calls then '
'the CDE will attemp to load the UI at the same place.'
"and folder the user was on. If the client provides the `server_context` in subsequent calls then "
"the CDE will attemp to load the UI at the same place."
)
supported_file_extensions: Optional[List[str]] = Field(
description='The client may optionally provide an array of accepted file extensions that should be opened '
'during this flow. The CDE server UI should make an attempt to only show files matching these '
'extensions to the user for the download selection or help the user in selecting the desired '
'files. However, the server does not have to guarantee that only files matching the extensions '
'will be selected. The extensions here must contain the dot separator.',
example=['.ifc', '.ifczip']
description="The client may optionally provide an array of accepted file extensions that should be opened "
"during this flow. The CDE server UI should make an attempt to only show files matching these "
"extensions to the user for the download selection or help the user in selecting the desired "
"files. However, the server does not have to guarantee that only files matching the extensions "
"will be selected. The extensions here must contain the dot separator.",
example=[".ifc", ".ifczip"],
)
class DataType(Enum):
string = 'string'
boolean = 'boolean'
date_time = 'date-time'
date = 'date'
integer32 = 'integer32'
integer64 = 'integer64'
number = 'number'
url = 'url'
string = "string"
boolean = "boolean"
date_time = "date-time"
date = "date"
integer32 = "integer32"
integer64 = "integer64"
number = "number"
url = "url"
class DocumentMetadataEntry(BaseModel):
name: constr(min_length=1) = Field(
description='The name of the metadata property'
)
value: List[constr(min_length=1)] = Field(
description='The value of the metadata property, can be a list'
)
data_type: DataType = Field(
description='The data type of the items in the value array'
)
name: constr(min_length=1) = Field(description="The name of the metadata property")
value: List[constr(min_length=1)] = Field(description="The value of the metadata property, can be a list")
data_type: DataType = Field(description="The data type of the items in the value array")
@@ -13,20 +13,18 @@ from models.documents_common import DocumentVersion, LinkData
class DocumentUploadSessionInitialization(BaseModel):
upload_ui_url: constr(min_length=1) = Field(
description='A CDE UI URL for the client to open in a local browser. The user would enter document metadata '
'directly in the CDE'
)
expires_in: int = Field(
description='`upload_ui_url` expiry in seconds'
description="A CDE UI URL for the client to open in a local browser. The user would enter document metadata "
"directly in the CDE"
)
expires_in: int = Field(description="`upload_ui_url` expiry in seconds")
max_size_in_bytes: int = Field(
description='The maximum file size supported by the CDE. Attempts to upload a larger file will fail'
description="The maximum file size supported by the CDE. Attempts to upload a larger file will fail"
)
class HttpMethod(Enum):
POST = 'POST'
PUT = 'PUT'
POST = "POST"
PUT = "PUT"
class HeaderValue(BaseModel):
@@ -40,12 +38,12 @@ class Headers(BaseModel):
class MultipartFormData(BaseModel):
prefix: str = Field(
description='This is a server provided value. Its value must be prefixed to the binary content body when '
'uploading this part'
description="This is a server provided value. Its value must be prefixed to the binary content body when "
"uploading this part"
)
suffix: str = Field(
description='This is a server provided value. Its value must be suffixed to the binary content body when '
'uploading this part. Typically, this is the end boundary for a multipart/form-data request'
description="This is a server provided value. Its value must be suffixed to the binary content body when "
"uploading this part. Typically, this is the end boundary for a multipart/form-data request"
)
@@ -54,26 +52,22 @@ class UploadFilePartInstruction(BaseModel):
http_method: HttpMethod
additional_headers: Optional[Headers] = None
include_authorization: Optional[bool] = Field(
description='Whether or not to include the authorization request header in the file upload request. '
'Including the authorization header with some cloud storage providers might fail the request'
description="Whether or not to include the authorization request header in the file upload request. "
"Including the authorization header with some cloud storage providers might fail the request"
)
multipart_form_data: Optional[MultipartFormData] = None
content_range_start: int = Field(
description='The inclusive, zero index based start for this part'
)
content_range_end: int = Field(
description='The inclusive, zero index based end for this part'
)
content_range_start: int = Field(description="The inclusive, zero index based start for this part")
content_range_end: int = Field(description="The inclusive, zero index based end for this part")
class DocumentToUpload(BaseModel):
session_file_id: constr(min_length=1) = Field(
description='A client-provided identifier that allows matching the specification with the correct file on the '
"user's machine"
description="A client-provided identifier that allows matching the specification with the correct file on the "
"user's machine"
)
upload_file_parts: List[UploadFilePartInstruction] = Field(
description='An array of request specifications detailing how to split the file to parts and upload each part '
'to the CDE'
description="An array of request specifications detailing how to split the file to parts and upload each part "
"to the CDE"
# min_length=1,
)
upload_completion: LinkData
@@ -83,8 +77,8 @@ class DocumentToUpload(BaseModel):
class DocumentsToUpload(BaseModel):
server_context: Optional[str] = Field(
description="A CDE controlled identifier recording the user's context on the CDE. For example which project "
'and folder the user was on. If the client provides the `server_context` in subsequent calls then '
'the CDE will attemp to load the UI at the same place.'
"and folder the user was on. If the client provides the `server_context` in subsequent calls then "
"the CDE will attemp to load the UI at the same place."
)
documents_to_upload: Optional[List[DocumentToUpload]]
@@ -94,12 +88,10 @@ class DocumentsToUpload(BaseModel):
class DocumentDiscoverySessionInitialization(BaseModel):
select_documents_url: constr(min_length=1) = Field(
description='A CDE UI URL for the client to open in a local browser. The user would search and select '
'documents directly in the CDE'
)
expires_in: int = Field(
description='`select_documents_url` expiry in seconds'
description="A CDE UI URL for the client to open in a local browser. The user would search and select "
"documents directly in the CDE"
)
expires_in: int = Field(description="`select_documents_url` expiry in seconds")
class DocumentsMarkedAsSelected(BaseModel):
@@ -109,29 +101,25 @@ class DocumentsMarkedAsSelected(BaseModel):
class SelectedDocuments(BaseModel):
server_context: Optional[str] = Field(
description="A CDE controlled identifier recording the user's context on the CDE. For example which project "
'and folder the user was on. If the client provides the `server_context` in subsequent calls then '
'the CDE will attemp to load the UI at the same place.'
)
documents: List[DocumentVersion] = Field(
description='An array containing all the documents selected by the user'
"and folder the user was on. If the client provides the `server_context` in subsequent calls then "
"the CDE will attemp to load the UI at the same place."
)
documents: List[DocumentVersion] = Field(description="An array containing all the documents selected by the user")
class DocumentMetadata(BaseModel):
session_file_id: constr(min_length=1) = Field(
description='This is a client provided id to differentiate between multiple files that are being uploaded in '
'the same session'
description="This is a client provided id to differentiate between multiple files that are being uploaded in "
"the same session"
)
document_id: Optional[constr(min_length=1)] = Field(
description='When present, indicates that this upload is a new version of an existing document'
description="When present, indicates that this upload is a new version of an existing document"
)
version_number: constr(min_length=1) = Field(
description='A human readable version number. This is not expected to be in any specific format across CDEs '
'and may hold any value'
)
title: constr(min_length=1) = Field(
description='A human readable code or identifier'
description="A human readable version number. This is not expected to be in any specific format across CDEs "
"and may hold any value"
)
title: constr(min_length=1) = Field(description="A human readable code or identifier")
project: Optional[str]
@@ -1,4 +1 @@
from pydantic import BaseModel
File diff suppressed because it is too large Load Diff
+281 -278
View File
@@ -25,41 +25,42 @@ class DOCDB(MyDB):
def document_node_to_model(self, document_node):
document_json = self.node_to_json(document_node)
document_json['creation_date'] = self.bcf_time(document_json['creation_date'])
document_json['file_description'] = {
'name': document_json.pop('name', '<no name>'),
'size_in_bytes': document_json.pop('size_in_bytes', 0)
document_json["creation_date"] = self.bcf_time(document_json["creation_date"])
document_json["file_description"] = {
"name": document_json.pop("name", "<no name>"),
"size_in_bytes": document_json.pop("size_in_bytes", 0),
}
document_json['links'] = self.document_version_links(document_json)
document_json["links"] = self.document_version_links(document_json)
return DocumentVersion(**document_json)
def get_document(self, document_id, version_index=False):
def get_document_work(tx) -> Union[Document, bool]:
if version_index is None or version_index is False or not isinstance(version_index, int):
version_index_criteria = ''
version_index_criteria = ""
else:
version_index_criteria = 'AND d.version_index = $version_index'
version_index_criteria = "AND d.version_index = $version_index"
cypher = """
cypher = (
"""
MATCH (d:Document)
WHERE d.document_id = $document_id
%s
RETURN d AS document
ORDER by d.version_index DESC
LIMIT 1
""" % version_index_criteria
"""
% version_index_criteria
)
result = tx.run(cypher,
document_id=document_id,
version_index=version_index)
result = tx.run(cypher, document_id=document_id, version_index=version_index)
first = result.single()
if first is None:
print('There were no such document version.')
print("There were no such document version.")
return False
document_node = first.get('document')
document_node = first.get("document")
return self.document_node_to_model(document_node)
with self.driver.session() as session:
@@ -88,21 +89,23 @@ class DOCDB(MyDB):
d.name = $name,
d.size_in_bytes = $size_in_bytes
"""
result = tx.run(cypher,
selection_session=selection_session,
project=project,
document_id=document_version.document_id,
session_file_id=document_version.session_file_id,
version_index=document_version.version_index,
version_number=document_version.version_number,
creation_date=document_version.creation_date,
title=document_version.title,
original_file_name=document_version.original_file_name,
file_ending=document_version.file_ending,
mime_type=document_version.mime_type,
file_type=document_version.file_type,
name=document_version.file_description.name,
size_in_bytes=document_version.file_description.size_in_bytes)
result = tx.run(
cypher,
selection_session=selection_session,
project=project,
document_id=document_version.document_id,
session_file_id=document_version.session_file_id,
version_index=document_version.version_index,
version_number=document_version.version_number,
creation_date=document_version.creation_date,
title=document_version.title,
original_file_name=document_version.original_file_name,
file_ending=document_version.file_ending,
mime_type=document_version.mime_type,
file_type=document_version.file_type,
name=document_version.file_description.name,
size_in_bytes=document_version.file_description.size_in_bytes,
)
summary = result.consume()
if summary.counters.nodes_created < 1:
@@ -122,10 +125,10 @@ class DOCDB(MyDB):
first = result.single()
if first is None:
print('There were no such document version.')
print("There were no such document version.")
return False
document_node = first.get('document')
document_node = first.get("document")
return self.document_node_to_model(document_node)
with self.driver.session() as session:
@@ -134,20 +137,21 @@ class DOCDB(MyDB):
def create_ifc_graph_for_document(self, document_id):
document = self.get_document(document_id)
my_ifc_file = ifcopenshell.open('./data/documents/' + document.file_description.name)
my_graph = Graph(os.environ['NEO4J_URI'], auth=(os.environ['NEO4J_USER'], os.environ['NEO4J_INITIAL_PASSWORD']))
my_ifc_file = ifcopenshell.open("./data/documents/" + document.file_description.name)
my_graph = Graph(os.environ["NEO4J_URI"], auth=(os.environ["NEO4J_USER"], os.environ["NEO4J_INITIAL_PASSWORD"]))
create_full_graph(my_graph, my_ifc_file)
# ---- UPLOAD FUNCTIONS ----
def post_upload_documents(self, upload_documents: UploadDocuments,
current_user: User) -> DocumentUploadSessionInitialization:
def post_upload_documents(
self, upload_documents: UploadDocuments, current_user: User
) -> DocumentUploadSessionInitialization:
def post_upload_documents_work(tx) -> DocumentUploadSessionInitialization:
session_uuid = str(uuid4())
session_callback_timedelta = int(upload_documents.callback.expires_in)
session_url_validity_timedelta = 10 + int(os.environ['SESSION_URL_VALIDITY_SECONDS'])
if not hasattr(upload_documents, 'server_context') or not upload_documents.server_context:
session_url_validity_timedelta = 10 + int(os.environ["SESSION_URL_VALIDITY_SECONDS"])
if not hasattr(upload_documents, "server_context") or not upload_documents.server_context:
upload_documents.server_context = False
cypher = """
@@ -165,13 +169,15 @@ class DOCDB(MyDB):
s.session_callback_timedelta = $session_callback_timedelta
"""
result = tx.run(cypher,
username=current_user.username,
session_callback_timedelta=session_callback_timedelta,
session_url_timedelta=session_url_validity_timedelta,
server_context=upload_documents.server_context,
upload_session=session_uuid,
callback=upload_documents.callback.url)
result = tx.run(
cypher,
username=current_user.username,
session_callback_timedelta=session_callback_timedelta,
session_url_timedelta=session_url_validity_timedelta,
server_context=upload_documents.server_context,
upload_session=session_uuid,
callback=upload_documents.callback.url,
)
summary = result.consume()
if summary.counters.nodes_created < 2:
@@ -197,54 +203,60 @@ class DOCDB(MyDB):
d.file_type = $file_type
"""
if not hasattr(file, 'document_id') or not file.document_id:
if not hasattr(file, "document_id") or not file.document_id:
# When document_id is present, this indicates that
# this upload is a new version of an existing document.
# When not present, we create a new uuid as new document_id.
file.document_id = doc_db.new_uuid()
if file.file_name.lower().endswith(tuple(file_types)):
file_ending = file.file_name.split('.')[-1].lower()
name = file.document_id + '.' + file_ending
file_ending = file.file_name.split(".")[-1].lower()
name = file.document_id + "." + file_ending
else:
file_ending = ''
file_ending = ""
name = file.document_id
print('File ending: ', file_ending)
print("File ending: ", file_ending)
mime_type = ''
file_type = ''
mime_type = ""
file_type = ""
if hasattr(file_types, file_ending):
print('We have this file ending in dict: ', file_ending)
print("We have this file ending in dict: ", file_ending)
mime_type = file_types[file_ending]['mime_type']
file_type = file_types[file_ending]['file_type']
mime_type = file_types[file_ending]["mime_type"]
file_type = file_types[file_ending]["file_type"]
result = tx.run(cypher,
username=current_user.username,
upload_session=session_uuid,
session_callback_timedelta=session_callback_timedelta,
original_file_name=file.file_name,
name=name,
session_file_id=file.session_file_id,
document_id=file.document_id,
creation_date=doc_db.timestamp(),
file_ending=file_ending,
mime_type=mime_type,
file_type=file_type)
result = tx.run(
cypher,
username=current_user.username,
upload_session=session_uuid,
session_callback_timedelta=session_callback_timedelta,
original_file_name=file.file_name,
name=name,
session_file_id=file.session_file_id,
document_id=file.document_id,
creation_date=doc_db.timestamp(),
file_ending=file_ending,
mime_type=mime_type,
file_type=file_type,
)
summary = result.consume()
if summary.counters.nodes_created < 1:
raise HTTPException(status_code=400, detail="Document node was not created.")
session_init = DocumentUploadSessionInitialization(**{
'upload_ui_url': os.environ['KONTROLL_BASE_URL'] + 'documents/1.0/' \
+ "document-upload?upload_session=" + session_uuid,
'expires_in': os.environ['SESSION_URL_VALIDITY_SECONDS'],
'max_size_in_bytes': os.environ['SESSION_MAX_FILE_SIZE_BYTES'],
})
session_init = DocumentUploadSessionInitialization(
**{
"upload_ui_url": os.environ["KONTROLL_BASE_URL"]
+ "documents/1.0/"
+ "document-upload?upload_session="
+ session_uuid,
"expires_in": os.environ["SESSION_URL_VALIDITY_SECONDS"],
"max_size_in_bytes": os.environ["SESSION_MAX_FILE_SIZE_BYTES"],
}
)
return session_init
@@ -261,15 +273,14 @@ class DOCDB(MyDB):
WHERE us.upload_session = $upload_session
RETURN d AS document
"""
results = tx.run(cypher,
upload_session=str(upload_session))
results = tx.run(cypher, upload_session=str(upload_session))
document_list = list()
for result in results:
document_json = self.node_to_json(result.get('document'))
document_json = self.node_to_json(result.get("document"))
file_to_upload = {
'file_name': document_json['original_file_name'],
'session_file_id': document_json['session_file_id'],
'document_id': document_json['document_id']
"file_name": document_json["original_file_name"],
"session_file_id": document_json["session_file_id"],
"document_id": document_json["document_id"],
}
document_model = FileToUpload(**file_to_upload)
document_list.append(document_model)
@@ -280,16 +291,15 @@ class DOCDB(MyDB):
WHERE us.upload_session = $upload_session
RETURN p AS project
"""
results = tx.run(cypher,
upload_session=str(upload_session))
results = tx.run(cypher, upload_session=str(upload_session))
project_list = list()
for result in results:
project_json = self.node_to_json(result.get('project'))
project_json = self.node_to_json(result.get("project"))
project = {
'project_id': project_json['project_id'],
'name': project_json['name'],
"project_id": project_json["project_id"],
"name": project_json["name"],
}
print('Project: ', project)
print("Project: ", project)
project_list.append(project)
# to get the user and some session data
@@ -302,31 +312,30 @@ class DOCDB(MyDB):
us.session_callback_timedelta AS session_callback_timedelta,
u AS user
"""
result = tx.run(cypher,
upload_session=str(upload_session))
result = tx.run(cypher, upload_session=str(upload_session))
first = result.single()
if first is None:
raise HTTPException(status_code=401, detail="No session or link.")
user_node = first.get('user')
user_node = first.get("user")
user_dict = self.node_to_json(user_node)
for_upload_documents_dict = dict()
for_upload_documents_dict['server_context'] = first.get('server_context')
for_upload_documents_dict["server_context"] = first.get("server_context")
callback_link = dict()
callback_link['url'] = first.get('callback')
callback_link['expires_in'] = first.get('session_callback_timedelta')
callback_link["url"] = first.get("callback")
callback_link["expires_in"] = first.get("session_callback_timedelta")
for_upload_documents_dict['callback'] = callback_link
for_upload_documents_dict['documents'] = document_list
print('Project list: ', project_list)
for_upload_documents_dict["callback"] = callback_link
for_upload_documents_dict["documents"] = document_list
print("Project list: ", project_list)
for_upload_documents_dict['projects'] = project_list
for_upload_documents_dict['current_user'] = user_dict
for_upload_documents_dict["projects"] = project_list
for_upload_documents_dict["current_user"] = user_dict
print('Documents list:', document_list)
print("Documents list:", document_list)
for_upload_documents_model = DataForUploadDocuments(**for_upload_documents_dict)
@@ -348,14 +357,16 @@ class DOCDB(MyDB):
d.title = $title,
d.project = $project
"""
result = tx.run(cypher,
username=username,
upload_session=upload_session,
session_file_id=document.session_file_id,
version_number=document.version_number,
version_index=False,
title=document.title,
project=document.project)
result = tx.run(
cypher,
username=username,
upload_session=upload_session,
session_file_id=document.session_file_id,
version_number=document.version_number,
version_index=False,
title=document.title,
project=document.project,
)
summary = result.consume()
if summary.counters.properties_set < 4:
@@ -376,11 +387,13 @@ class DOCDB(MyDB):
SET
d.size_in_bytes = $size_in_bytes
"""
result = tx.run(cypher,
username=user.username,
upload_session=upload_session,
session_file_id=document.session_file_id,
size_in_bytes=document.size_in_bytes)
result = tx.run(
cypher,
username=user.username,
upload_session=upload_session,
session_file_id=document.session_file_id,
size_in_bytes=document.size_in_bytes,
)
summary = result.consume()
if summary.counters.properties_set < 1:
raise HTTPException(status_code=400, detail="Property was not set.")
@@ -390,18 +403,20 @@ class DOCDB(MyDB):
session.execute_write(update_file_size_work)
# link creation
base_url = os.environ['KONTROLL_BASE_URL'] + 'documents/1.0/'
upload_session_url = '?upload_session=' + upload_session
upload_complete_url = base_url + 'upload-completion' + upload_session_url
upload_cancellation_url = base_url + 'upload-cancellation' + upload_session_url
upload_completion = LinkData(**{'url': upload_complete_url})
upload_cancellation = LinkData(**{'url': upload_cancellation_url})
document_to_upload_model = DocumentToUpload(**{
'session_file_id': document.session_file_id,
'upload_file_parts': list(),
'upload_completion': upload_completion,
'upload_cancellation': upload_cancellation
})
base_url = os.environ["KONTROLL_BASE_URL"] + "documents/1.0/"
upload_session_url = "?upload_session=" + upload_session
upload_complete_url = base_url + "upload-completion" + upload_session_url
upload_cancellation_url = base_url + "upload-cancellation" + upload_session_url
upload_completion = LinkData(**{"url": upload_complete_url})
upload_cancellation = LinkData(**{"url": upload_cancellation_url})
document_to_upload_model = DocumentToUpload(
**{
"session_file_id": document.session_file_id,
"upload_file_parts": list(),
"upload_completion": upload_completion,
"upload_cancellation": upload_cancellation,
}
)
def add_part_work(tx) -> UUID:
cypher = """
@@ -416,15 +431,17 @@ class DOCDB(MyDB):
p.content_range_end = $content_range_end,
p.content_length = $content_length
"""
result = tx.run(cypher,
username=user.username,
upload_session=upload_session,
session_file_id=document.session_file_id,
part_number=part_number,
part_uuid=str(upload_part_uuid),
content_range_start=content_range_start,
content_range_end=content_range_end,
content_length=content_length)
result = tx.run(
cypher,
username=user.username,
upload_session=upload_session,
session_file_id=document.session_file_id,
part_number=part_number,
part_uuid=str(upload_part_uuid),
content_range_start=content_range_start,
content_range_end=content_range_end,
content_length=content_length,
)
summary = result.consume()
if summary.counters.nodes_created != 1:
@@ -432,7 +449,7 @@ class DOCDB(MyDB):
return upload_part_uuid
# calculate the number of file parts to send
number_of_parts = math.ceil(int(document.size_in_bytes) / int(os.environ['SESSION_MAX_FILE_SIZE_BYTES']))
number_of_parts = math.ceil(int(document.size_in_bytes) / int(os.environ["SESSION_MAX_FILE_SIZE_BYTES"]))
part_length = math.ceil(int(document.size_in_bytes) / number_of_parts)
for part_number in range(number_of_parts):
content_range_start = part_number * part_length
@@ -441,23 +458,18 @@ class DOCDB(MyDB):
content_range_end = document.size_in_bytes - 1
content_length = content_range_end - content_range_start + 1
upload_part_uuid = uuid4()
upload_part_url = 'upload-part/' + str(upload_part_uuid)
additional_headers = {
'values': [
{
'name': 'Content-Length',
'value': content_length
}
]
}
part_instruction = UploadFilePartInstruction(**{
'url': base_url + upload_part_url,
'http_method': 'POST',
'additional_headers': additional_headers,
'include_authorization': True,
'content_range_start': content_range_start,
'content_range_end': content_range_end
})
upload_part_url = "upload-part/" + str(upload_part_uuid)
additional_headers = {"values": [{"name": "Content-Length", "value": content_length}]}
part_instruction = UploadFilePartInstruction(
**{
"url": base_url + upload_part_url,
"http_method": "POST",
"additional_headers": additional_headers,
"include_authorization": True,
"content_range_start": content_range_start,
"content_range_end": content_range_end,
}
)
with self.driver.session() as session:
added_part = session.execute_write(add_part_work)
@@ -476,19 +488,17 @@ class DOCDB(MyDB):
RETURN d AS document
"""
result = tx.run(cypher,
username=current_user.username,
part_id=part_id)
result = tx.run(cypher, username=current_user.username, part_id=part_id)
first = result.single()
if first is None:
print('There were no parts in graph!')
print("There were no parts in graph!")
return False
document_node = first.get('document')
document_node = first.get("document")
document = self.document_node_to_model(document_node)
print('User had this part ' + part_id + ' in document id: ' + document.document_id)
print("User had this part " + part_id + " in document id: " + document.document_id)
return document
with self.driver.session() as session:
@@ -503,9 +513,7 @@ class DOCDB(MyDB):
SET p.uploaded = True
"""
result = tx.run(cypher,
username=current_user.username,
part_id=part_id)
result = tx.run(cypher, username=current_user.username, part_id=part_id)
summary = result.consume()
if summary.counters.properties_set < 1:
@@ -526,26 +534,24 @@ class DOCDB(MyDB):
RETURN count(p) as parts
"""
result = tx.run(cypher,
username=current_user.username,
upload_session=upload_session)
result = tx.run(cypher, username=current_user.username, upload_session=upload_session)
first = result.single()
if first is None:
return False
number_of_parts = first.get('parts')
number_of_parts = first.get("parts")
print('There are number of parts not uploaded: ', number_of_parts)
print("There are number of parts not uploaded: ", number_of_parts)
if number_of_parts > 0:
raise HTTPException(status_code=400, detail="All parts not uploaded.")
else:
return True
with self.driver.session() as session:
return session.execute_read(check_uploaded_parts_work)
def retrieve_uploaded_parts(self, upload_session: str, current_user: User) -> list:
def retrieve_uploaded_parts_work(tx) -> list:
cypher = """
@@ -556,14 +562,12 @@ class DOCDB(MyDB):
RETURN p as part
ORDER BY part.number
"""
results = tx.run(cypher,
username=current_user.username,
upload_session=upload_session)
results = tx.run(cypher, username=current_user.username, upload_session=upload_session)
parts_list = list()
for result in results:
part_json = self.node_to_json(result.get("part"))
parts_list.append(part_json['uuid'])
parts_list.append(part_json["uuid"])
return parts_list
with self.driver.session() as session:
@@ -579,12 +583,10 @@ class DOCDB(MyDB):
RETURN d AS document
"""
result = tx.run(cypher,
username=current_user.username,
upload_session=upload_session)
result = tx.run(cypher, username=current_user.username, upload_session=upload_session)
first = result.single()
document_node = first.get('document')
document_node = first.get("document")
return self.document_node_to_model(document_node)
with self.driver.session() as session:
@@ -604,10 +606,7 @@ class DOCDB(MyDB):
DELETE r2
CREATE (proj)-[r4:CONTAINS]->(d)
"""
result = tx.run(cypher,
username=current_user.username,
upload_session=upload_session,
project=project)
result = tx.run(cypher, username=current_user.username, upload_session=upload_session, project=project)
summary = result.consume()
if summary.counters.nodes_deleted < 1:
@@ -627,15 +626,13 @@ class DOCDB(MyDB):
AND us.upload_session = $upload_session
RETURN d as document
"""
result = tx.run(cypher,
username=current_user.username,
upload_session=upload_session)
result = tx.run(cypher, username=current_user.username, upload_session=upload_session)
first = result.single()
if first is None:
return False
document_node = first.get('document')
document_node = first.get("document")
return self.document_node_to_model(document_node)
def upload_cancellation_work(tx) -> bool:
@@ -645,9 +642,7 @@ class DOCDB(MyDB):
AND us.upload_session = $upload_session
DETACH DELETE us, d, p
"""
result = tx.run(cypher,
username=current_user.username,
upload_session=upload_session)
result = tx.run(cypher, username=current_user.username, upload_session=upload_session)
summary = result.consume()
if summary.counters.nodes_deleted < 1:
@@ -662,14 +657,15 @@ class DOCDB(MyDB):
# ---- DOWNLOAD FUNCTIONS ----
def post_select_documents(self, select_documents: SelectDocuments,
current_user: User) -> DocumentDiscoverySessionInitialization:
def post_select_documents(
self, select_documents: SelectDocuments, current_user: User
) -> DocumentDiscoverySessionInitialization:
def post_select_documents_work(tx) -> DocumentDiscoverySessionInitialization:
session_uuid = str(uuid4())
session_callback_timedelta = int(select_documents.callback.expires_in)
session_url_validity_timedelta = 10 + int(os.environ['SESSION_URL_VALIDITY_SECONDS'])
if not hasattr(select_documents, 'server_context') or not select_documents.server_context:
session_url_validity_timedelta = 10 + int(os.environ["SESSION_URL_VALIDITY_SECONDS"])
if not hasattr(select_documents, "server_context") or not select_documents.server_context:
select_documents.server_context = str(uuid4())
cypher = """
@@ -687,22 +683,28 @@ class DOCDB(MyDB):
s.session_callback_timedelta = $session_callback_timedelta
"""
result = tx.run(cypher,
username=current_user.username,
session_callback_timedelta=session_callback_timedelta,
session_url_timedelta=session_url_validity_timedelta,
server_context=select_documents.server_context,
selection_session=str(session_uuid),
callback=select_documents.callback.url)
result = tx.run(
cypher,
username=current_user.username,
session_callback_timedelta=session_callback_timedelta,
session_url_timedelta=session_url_validity_timedelta,
server_context=select_documents.server_context,
selection_session=str(session_uuid),
callback=select_documents.callback.url,
)
summary = result.consume()
if summary.counters.nodes_created < 2:
raise HTTPException(status_code=400, detail="Session or link node was not created.")
session_init_dict = dict()
session_init_dict['select_documents_url'] = os.environ['KONTROLL_BASE_URL'] + 'documents/1.0/' \
+ "document-selection?selection_session=" + session_uuid
session_init_dict['expires_in'] = os.environ['SESSION_URL_VALIDITY_SECONDS']
session_init_dict["select_documents_url"] = (
os.environ["KONTROLL_BASE_URL"]
+ "documents/1.0/"
+ "document-selection?selection_session="
+ session_uuid
)
session_init_dict["expires_in"] = os.environ["SESSION_URL_VALIDITY_SECONDS"]
session_init_model = DocumentDiscoverySessionInitialization(**session_init_dict)
return session_init_model
@@ -719,13 +721,12 @@ class DOCDB(MyDB):
RETURN p AS project
ORDER BY project.name
"""
project_results = tx.run(cypher,
selection_session=str(selection_session))
project_results = tx.run(cypher, selection_session=str(selection_session))
project_list = list()
for project_result in project_results:
project_json = self.node_to_json(project_result.get('project'))
project_json['documents'] = list()
project_json = self.node_to_json(project_result.get("project"))
project_json["documents"] = list()
project_model = Project(**project_json)
# to get the documents
@@ -736,12 +737,12 @@ class DOCDB(MyDB):
RETURN d AS document
ORDER BY d.title, d.version_index
"""
document_results = tx.run(cypher,
selection_session=str(selection_session),
project_id=str(project_model.project_id))
document_results = tx.run(
cypher, selection_session=str(selection_session), project_id=str(project_model.project_id)
)
for document_result in document_results:
document_node = document_result.get('document')
document_node = document_result.get("document")
document_model = self.document_node_to_model(document_node)
project_model.documents.append(document_model)
@@ -758,8 +759,7 @@ class DOCDB(MyDB):
u AS user
"""
result = tx.run(cypher,
selection_session=str(selection_session))
result = tx.run(cypher, selection_session=str(selection_session))
first = result.single()
if first is None:
@@ -769,26 +769,28 @@ class DOCDB(MyDB):
user_dict = self.node_to_json(user_node)
for_document_selection_dict = dict()
for_document_selection_dict['server_context'] = first.get('server_context')
for_document_selection_dict["server_context"] = first.get("server_context")
callback_link = dict()
callback_link['url'] = first.get('callback')
callback_link['expires_in'] = first.get('session_callback_timedelta')
callback_link["url"] = first.get("callback")
callback_link["expires_in"] = first.get("session_callback_timedelta")
for_document_selection_dict['callback'] = callback_link
for_document_selection_dict['projects'] = project_list
for_document_selection_dict['current_user'] = user_dict
for_document_selection_dict["callback"] = callback_link
for_document_selection_dict["projects"] = project_list
for_document_selection_dict["current_user"] = user_dict
for_document_selection_model = DataForDocumentSelection(**for_document_selection_dict)
print('Data for document selection: ', for_document_selection_dict)
print("Data for document selection: ", for_document_selection_dict)
return for_document_selection_model
with self.driver.session() as session:
return session.execute_read(get_data_for_document_selection_work)
def post_mark_documents_as_selected(self, all_documents: list, selection_session: UUID) -> DocumentsMarkedAsSelected:
def post_mark_documents_as_selected(
self, all_documents: list, selection_session: UUID
) -> DocumentsMarkedAsSelected:
def mark_documents_as_selected_work(tx) -> DocumentsMarkedAsSelected:
cypher = """
@@ -798,12 +800,10 @@ class DOCDB(MyDB):
MERGE (ss)-[r5:SELECTED]->(d)
"""
selected_documents_model = DocumentsMarkedAsSelected(**{'documents': list()})
selected_documents_model = DocumentsMarkedAsSelected(**{"documents": list()})
for document in all_documents:
result = tx.run(cypher,
selection_session=str(selection_session),
document_id=str(document))
result = tx.run(cypher, selection_session=str(selection_session), document_id=str(document))
summary = result.consume()
@@ -817,16 +817,20 @@ class DOCDB(MyDB):
@staticmethod
def document_version_links(document_json):
document_id = document_json['document_id']
version_index = document_json['version_index']
base = os.environ['KONTROLL_BASE_URL'] + "documents/1.0/document/" + document_id + "/version/" + str(version_index)
return DocumentVersionLinks(**{
'document_version': LinkData(**{'url': base}),
'document_version_metadata': LinkData(**{'url': base + "/metadata"}),
'document_version_download': LinkData(**{'url': base + "/download"}),
'document_versions': LinkData(**{'url': base + "/versions"}),
'document_details': LinkData(**{'url': base + "/details"})
})
document_id = document_json["document_id"]
version_index = document_json["version_index"]
base = (
os.environ["KONTROLL_BASE_URL"] + "documents/1.0/document/" + document_id + "/version/" + str(version_index)
)
return DocumentVersionLinks(
**{
"document_version": LinkData(**{"url": base}),
"document_version_metadata": LinkData(**{"url": base + "/metadata"}),
"document_version_download": LinkData(**{"url": base + "/download"}),
"document_versions": LinkData(**{"url": base + "/versions"}),
"document_details": LinkData(**{"url": base + "/details"}),
}
)
def get_download_instructions(self, session_id: UUID, server_context: str, current_user: User) -> SelectedDocuments:
def get_download_instructions_work(tx) -> SelectedDocuments:
@@ -839,18 +843,16 @@ class DOCDB(MyDB):
document_list = list()
for result in results:
document_node = result.get('document')
document_node = result.get("document")
document_model = self.document_node_to_model(document_node)
document_list.append(document_model)
selected_documents = SelectedDocuments(**{'server_context': server_context,
'documents': document_list})
selected_documents = SelectedDocuments(**{"server_context": server_context, "documents": document_list})
return selected_documents
with self.driver.session() as session:
return session.execute_read(get_download_instructions_work)
def get_upload_documents(self, upload_session: UUID, current_user: User) -> UploadDocuments:
def get_upload_documents_work(tx) -> UploadDocuments:
cypher = """
@@ -860,12 +862,10 @@ class DOCDB(MyDB):
AND us.upload_session = $upload_session
RETURN d AS document
"""
results = tx.run(cypher,
username=current_user.username,
upload_session=upload_session)
results = tx.run(cypher, username=current_user.username, upload_session=upload_session)
file_list = list()
for result in results:
file_json = self.node_to_json(result.get('document'))
file_json = self.node_to_json(result.get("document"))
file_model = FileToUpload(**file_json)
file_list.append(file_model)
@@ -878,16 +878,14 @@ class DOCDB(MyDB):
us.callback AS callback,
us.session_callback_timedelta
"""
result = tx.run(cypher,
username=current_user.username,
upload_session=upload_session)
result = tx.run(cypher, username=current_user.username, upload_session=upload_session)
callback = result.get('callback')
session_callback_timedelta = result.get('session_callback_timedelta')
callback = result.get("callback")
session_callback_timedelta = result.get("session_callback_timedelta")
upload_documents = UploadDocuments()
upload_documents.server_context = result.get('server_context')
upload_documents.callback.url = result.get('callback')
upload_documents.server_context = result.get("server_context")
upload_documents.callback.url = result.get("callback")
upload_documents.callback.expires_in = 3500 # difference between now and timedelta
upload_documents.files = file_list
@@ -896,16 +894,18 @@ class DOCDB(MyDB):
with self.driver.session() as session:
return session.execute_read(get_upload_documents_work)
def get_document_version(self, document_id: UUID, version_index: int,
current_user: User) -> Union[DocumentVersion, bool]:
def get_document_version(
self, document_id: UUID, version_index: int, current_user: User
) -> Union[DocumentVersion, bool]:
def get_document_version_work(tx) -> Union[DocumentVersion, bool]:
if version_index is None or version_index is False or not isinstance(version_index, int):
version_index_criteria = 'AND d.version_index = $version_index'
version_index_criteria = "AND d.version_index = $version_index"
else:
version_index_criteria = ''
version_index_criteria = ""
cypher = """
cypher = (
"""
MATCH (u:User)-[r3:HAS_ACTIONS_ON]->(p:Project)-[r4:CONTAINS]->(d:Document)
WHERE u.username = $username
AND d.document_id = $document_id
@@ -913,19 +913,20 @@ class DOCDB(MyDB):
RETURN d AS document
ORDER by d.version_index DESC
LIMIT 1
""" % version_index_criteria
"""
% version_index_criteria
)
result = tx.run(cypher,
username=current_user.username,
document_id=document_id,
version_index=version_index)
result = tx.run(
cypher, username=current_user.username, document_id=document_id, version_index=version_index
)
first = result.single()
if first is None:
print('There were no such document version.')
print("There were no such document version.")
return False
document_node = first.get('document')
document_node = first.get("document")
return self.document_node_to_model(document_node)
with self.driver.session() as session:
@@ -935,11 +936,12 @@ class DOCDB(MyDB):
def get_document_version_metadata_work(tx) -> DocumentMetadataEntries:
if version_index is None or version_index is False or not isinstance(version_index, int):
version_index_criteria = 'AND d.version_index = $version_index'
version_index_criteria = "AND d.version_index = $version_index"
else:
version_index_criteria = ''
version_index_criteria = ""
cypher = """
cypher = (
"""
MATCH (u:User)-[r3:HAS_ACTIONS_ON]->(p:Project)-[r4:CONTAINS]->(d:Document)
WHERE u.username = $username
AND d.document_id = $document_id
@@ -947,32 +949,34 @@ class DOCDB(MyDB):
RETURN d AS document
ORDER by d.version_index DESC
LIMIT 1
""" % version_index_criteria
"""
% version_index_criteria
)
result = tx.run(cypher,
username=current_user.username,
document_id=document_id,
version_index=version_index)
result = tx.run(
cypher, username=current_user.username, document_id=document_id, version_index=version_index
)
first = result.single()
if first is None:
print('There were no such document version.')
print("There were no such document version.")
return False
document_json = self.node_to_json(first.get('document'))
document_json['creation_date'] = self.bcf_time(document_json['creation_date'])
metadata = ['title', 'version_number', 'creation_date']
document_json = self.node_to_json(first.get("document"))
document_json["creation_date"] = self.bcf_time(document_json["creation_date"])
metadata = ["title", "version_number", "creation_date"]
entries = list()
for each_metadata in metadata:
each_metadata_text = each_metadata.replace('_', ' ')
each_metadata_text = each_metadata.replace("_", " ")
each_metadata_text = each_metadata_text.capitalize()
entry = {
'name': each_metadata_text,
'value': [document_json[each_metadata]],
'data_type': DataType.string
"name": each_metadata_text,
"value": [document_json[each_metadata]],
"data_type": DataType.string,
}
entries.append(entry)
return DocumentMetadataEntries(**{'metadata': entries})
return DocumentMetadataEntries(**{"metadata": entries})
with self.driver.session() as session:
return session.execute_read(get_document_version_metadata_work)
@@ -984,15 +988,14 @@ class DOCDB(MyDB):
AND d.document_id = $document_id
RETURN d AS document
"""
results = tx.run(cypher,
username=current_user.username,
document_id=document_id)
document_versions = DocumentVersions({'documents': list()})
results = tx.run(cypher, username=current_user.username, document_id=document_id)
document_versions = DocumentVersions({"documents": list()})
for result in results:
document_json = self.node_to_json(result.get('document'))
document_version = self.get_document_version(document_id, document_json['version_index'], current_user)
document_json = self.node_to_json(result.get("document"))
document_version = self.get_document_version(document_id, document_json["version_index"], current_user)
document_versions.documents.append(document_version)
return document_versions
with self.driver.session() as session:
return session.execute_read(get_document_versions_work)
@@ -36,11 +36,13 @@ class FoundationDB(MyDB):
CALL apoc.ttl.expireIn(ac, $time_delta, 's')
RETURN ac AS authorization_code
"""
result = tx.run(cypher,
username=username,
authorization_code=authorization_code,
scope=scope,
time_delta=int(os.environ['SECURITY_AUTHORIZATION_CODE_EXPIRE_SECONDS']))
result = tx.run(
cypher,
username=username,
authorization_code=authorization_code,
scope=scope,
time_delta=int(os.environ["SECURITY_AUTHORIZATION_CODE_EXPIRE_SECONDS"]),
)
summary = result.consume()
if summary.counters.nodes_created < 1:
raise HTTPException(status_code=400, detail="Authorization code was not created.")
@@ -58,14 +60,13 @@ class FoundationDB(MyDB):
RETURN
username, scope
"""
result = tx.run(cypher,
authorization_code=authorization_code)
result = tx.run(cypher, authorization_code=authorization_code)
first = result.single()
if first is None:
raise HTTPException(status_code=404, detail="Authorization code not found.")
authorized_user = TokenData()
authorized_user.username = first.get("username")
authorized_user.scopes = first.get("scope").split(' ')
authorized_user.scopes = first.get("scope").split(" ")
return authorized_user
with self.driver.session() as session:
@@ -73,11 +74,11 @@ class FoundationDB(MyDB):
token_info = TokenInfo()
token_info.access_token = create_access_token(
user_info.dict(),
timedelta(seconds=int(os.environ['SECURITY_ACCESS_TOKEN_EXPIRE_SECONDS'])))
user_info.dict(), timedelta(seconds=int(os.environ["SECURITY_ACCESS_TOKEN_EXPIRE_SECONDS"]))
)
token_info.refresh_token = create_access_token(
user_info.dict(),
timedelta(seconds=int(os.environ['SECURITY_REFRESH_TOKEN_EXPIRE_SECONDS'])))
user_info.dict(), timedelta(seconds=int(os.environ["SECURITY_REFRESH_TOKEN_EXPIRE_SECONDS"]))
)
def add_tokens_and_delete_code_work(tx) -> bool:
cypher = """
@@ -92,13 +93,15 @@ class FoundationDB(MyDB):
SET t3.value = $refresh_token
SET t3.hash = $refresh_token_hash
"""
result = tx.run(cypher,
authorization_code=authorization_code,
username=user_info.username,
access_token=token_info.access_token,
access_token_hash=hashlib.md5(token_info.access_token.encode('utf-8')).hexdigest(),
refresh_token=token_info.refresh_token,
refresh_token_hash=hashlib.md5(token_info.refresh_token.encode('utf-8')).hexdigest())
result = tx.run(
cypher,
authorization_code=authorization_code,
username=user_info.username,
access_token=token_info.access_token,
access_token_hash=hashlib.md5(token_info.access_token.encode("utf-8")).hexdigest(),
refresh_token=token_info.refresh_token,
refresh_token_hash=hashlib.md5(token_info.refresh_token.encode("utf-8")).hexdigest(),
)
summary = result.consume()
if summary.counters.nodes_created < 1 or summary.counters.nodes_deleted < 1:
@@ -119,24 +122,25 @@ class FoundationDB(MyDB):
RETURN
at.value AS access_token
"""
refresh_token_payload = jwt.decode(refresh_token,
secrets['security_secret_key'],
algorithms=[os.environ['SECURITY_ALGORITHM']])
refresh_token_payload = jwt.decode(
refresh_token, secrets["security_secret_key"], algorithms=[os.environ["SECURITY_ALGORITHM"]]
)
username_from_refresh_token: str = refresh_token_payload.get("username")
print('refresh_token_username: ', username_from_refresh_token)
result = tx.run(cypher,
username=username_from_refresh_token,
refresh_token_hash=hashlib.md5(refresh_token.encode('utf-8')).hexdigest()
)
print("refresh_token_username: ", username_from_refresh_token)
result = tx.run(
cypher,
username=username_from_refresh_token,
refresh_token_hash=hashlib.md5(refresh_token.encode("utf-8")).hexdigest(),
)
first = result.single()
if first is None:
raise HTTPException(status_code=404, detail="Access token not found.")
token_info = TokenInfo()
token_info.access_token = first.get("access_token")
token_info.refresh_token = refresh_token
access_token_payload = jwt.decode(token_info.access_token,
secrets['security_secret_key'],
algorithms=[os.environ['SECURITY_ALGORITHM']])
access_token_payload = jwt.decode(
token_info.access_token, secrets["security_secret_key"], algorithms=[os.environ["SECURITY_ALGORITHM"]]
)
username_from_access_token: str = access_token_payload.get("username")
if username_from_access_token is None:
raise credentials_exception
@@ -148,11 +152,11 @@ class FoundationDB(MyDB):
got_token_data, got_token_info = session.execute_read(use_refresh_to_get_access_work)
new_token_info = TokenInfo()
new_token_info.access_token = create_access_token(
got_token_data.dict(),
timedelta(seconds=int(os.environ['SECURITY_ACCESS_TOKEN_EXPIRE_SECONDS'])))
got_token_data.dict(), timedelta(seconds=int(os.environ["SECURITY_ACCESS_TOKEN_EXPIRE_SECONDS"]))
)
new_token_info.refresh_token = create_access_token(
got_token_data.dict(),
timedelta(seconds=int(os.environ['SECURITY_REFRESH_TOKEN_EXPIRE_SECONDS'])))
got_token_data.dict(), timedelta(seconds=int(os.environ["SECURITY_REFRESH_TOKEN_EXPIRE_SECONDS"]))
)
def update_tokens_work(tx) -> bool:
cypher = """
@@ -168,12 +172,14 @@ class FoundationDB(MyDB):
rt.hash = $refresh_token_hash,
at.hash = $access_token_hash
"""
result = tx.run(cypher,
username=got_token_data.username,
access_token=new_token_info.access_token,
refresh_token=new_token_info.refresh_token,
access_token_hash=hashlib.md5(new_token_info.access_token.encode('utf-8')).hexdigest(),
refresh_token_hash=hashlib.md5(new_token_info.refresh_token.encode('utf-8')).hexdigest())
result = tx.run(
cypher,
username=got_token_data.username,
access_token=new_token_info.access_token,
refresh_token=new_token_info.refresh_token,
access_token_hash=hashlib.md5(new_token_info.access_token.encode("utf-8")).hexdigest(),
refresh_token_hash=hashlib.md5(new_token_info.refresh_token.encode("utf-8")).hexdigest(),
)
summary = result.consume()
if summary.counters.nodes_created < 2 or summary.counters.nodes_deleted < 2:
raise HTTPException(status_code=400, detail="Tokens were not deleted and created.")
@@ -183,4 +189,5 @@ class FoundationDB(MyDB):
session.execute_write(update_tokens_work)
return new_token_info
foundation_db = FoundationDB(driver)
@@ -3,8 +3,8 @@ from glob import glob
def get_secrets():
secrets = dict()
for var in glob('/run/secrets/*'):
k = var.split('/')[-1]
v = open(var).read().rstrip('\n')
for var in glob("/run/secrets/*"):
k = var.split("/")[-1]
v = open(var).read().rstrip("\n")
secrets[k] = v
return secrets
+15 -22
View File
@@ -16,25 +16,20 @@ from security.secrets import get_secrets
secrets = get_secrets()
# password context
crypt_context = CryptContext(
schemes=["bcrypt"],
deprecated="auto")
crypt_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
oauth2_scheme = OAuth2AuthorizationCodeBearer(
authorizationUrl='foundation/oauth2/auth',
tokenUrl='foundation/oauth2/token',
scopes={
'test': 'Full access, but only test data.',
'user': 'Normal user access.',
'admin': 'Full access to all.'
})
authorizationUrl="foundation/oauth2/auth",
tokenUrl="foundation/oauth2/token",
scopes={"test": "Full access, but only test data.", "user": "Normal user access.", "admin": "Full access to all."},
)
credentials_exception = HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Could not validate credentials",
headers={"WWW-Authenticate": "Bearer"},
)
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Could not validate credentials",
headers={"WWW-Authenticate": "Bearer"},
)
def create_access_token(data: dict, expires_delta: timedelta | None = None):
@@ -44,7 +39,7 @@ def create_access_token(data: dict, expires_delta: timedelta | None = None):
else:
expire = datetime.utcnow() + timedelta(minutes=15)
payload.update({"expires": str(expire)})
encoded_jwt = jwt.encode(payload, secrets['security_secret_key'], algorithm=os.environ['SECURITY_ALGORITHM'])
encoded_jwt = jwt.encode(payload, secrets["security_secret_key"], algorithm=os.environ["SECURITY_ALGORITHM"])
return encoded_jwt
@@ -79,20 +74,18 @@ async def get_current_user(security_scopes: SecurityScopes, token: str = Depends
print(authenticate_value)
try:
print('Token: ', token)
payload = jwt.decode(token,
secrets['security_secret_key'],
algorithms=[os.environ['SECURITY_ALGORITHM']])
print("Token: ", token)
payload = jwt.decode(token, secrets["security_secret_key"], algorithms=[os.environ["SECURITY_ALGORITHM"]])
username_from_token: str = payload.get("username")
print('Token username: ', username_from_token)
print("Token username: ", username_from_token)
if username_from_token is None:
raise credentials_exception
token_scopes = payload.get("scopes", [])
print('Token scopes: ', token_scopes)
print("Token scopes: ", token_scopes)
token_data = TokenData(scopes=token_scopes, username=username_from_token)
except JWTError:
print('JWTError')
print("JWTError")
raise credentials_exception
user = db.get_user(username=token_data.username)