Files
IfcOpenShell/src/opencdeserver/api/app/repository/bcf.py
T

1475 lines
71 KiB
Python

import base64
import os
import jsonpickle
from fastapi import UploadFile, HTTPException
from uuid import UUID, uuid4
from database.neo4j import MyDB, driver
from models.bcf_request import *
from models.bcf_response import *
from models.request import *
class BCFDB(MyDB):
# implemented
def get_projects(self, current_user: User) -> List[ProjectGET]:
def get_projects_work(tx) -> List[ProjectGET]:
cypher = """
MATCH (u:User)-[r1:HAS_ACTIONS_ON]->(p:Project)
WHERE u.username = $username
AND r1.read = True
RETURN p AS project
"""
results = tx.run(cypher, username=current_user.username)
project_model_list = list()
for result in results:
project_json = self.node_to_json(result.get("project"))
project_model = ProjectGET(**project_json)
project_model_list.append(project_model)
return project_model_list
with self.driver.session() as session:
return session.execute_read(get_projects_work)
# implemented
def get_project(self, project_id: UUID, current_user: User) -> ProjectGET:
def get_project_work(tx) -> ProjectGET:
cypher = """
MATCH (u:User)-[r1:HAS_ACTIONS_ON]->(p:Project)
WHERE u.username = $username
AND r1.read = True
AND p.project_id = $project_id
RETURN p AS project
"""
result = tx.run(cypher,
username=current_user.username,
project_id=str(project_id))
first = result.single()
if first is None:
raise HTTPException(status_code=404, detail="Item not found.")
project_node = first.get("project")
project_dict = self.node_to_json(project_node)
return ProjectGET(**project_dict)
with self.driver.session() as session:
return session.execute_read(get_project_work)
# implemented
def put_project(self, project_id: UUID, project: ProjectPUT, current_user: User) -> ProjectGET:
def put_project_work(tx) -> ProjectGET:
cypher = """
MATCH (u:User)-[r1:HAS_ACTIONS_ON]->(p:Project)
WHERE u.username = $username
AND r1.update = True
AND p.project_id = $project_id
SET p.name = $project_name
RETURN p AS project
"""
result = tx.run(cypher,
username=current_user.username,
project_id=str(project_id),
project_name=project.name)
first = result.single()
if first is None:
raise HTTPException(status_code=404, detail="Item not found.")
project_node = first.get("project")
project_dict = self.node_to_json(project_node)
return ProjectGET(**project_dict)
with self.driver.session() as session:
return session.execute_write(put_project_work)
# implemented
def get_project_extensions(self, project_id: UUID, current_user: User) -> ExtensionsGET:
def get_project_extensions_work(tx) -> ExtensionsGET:
cypher = """
MATCH (u:User)-[r1:HAS_ACTIONS_ON]->(p:Project)-[r2:HAS]->(e:Extensions)
WHERE u.username = $username
AND r1.read = True
AND p.project_id = $project_id
RETURN e AS extensions
"""
result = tx.run(cypher,
username=current_user.username,
project_id=str(project_id))
first = result.single()
if first is None:
raise HTTPException(status_code=404, detail="Item not found.")
extensions_node = first.get("extensions")
extensions_dict = self.node_to_json(extensions_node)
return ExtensionsGET(**extensions_dict)
with self.driver.session() as session:
return session.execute_read(get_project_extensions_work)
# implemented
# returns a collection
def get_topics(self, project_id: str, current_user: User) -> List[TopicGET]:
def get_topics_work(tx) -> List[TopicGET]:
cypher = """
MATCH (u:User)-[r1:HAS_ACTIONS_ON]->(p:Project)-[r2:HAS]->(t:Topic)
WHERE u.username = $username
AND r1.read = True
AND p.project_id = $project_id
RETURN t AS topic, ID(t) AS server_assigned_id
"""
results = tx.run(cypher,
username=current_user.username,
project_id=str(project_id))
topic_model_list = list()
for result in results:
topic_json = self.node_to_json(result.get("topic"))
topic_json["server_assigned_id"] = result.get("server_assigned_id")
topic_model = TopicGET(**topic_json)
topic_model_list.append(topic_model)
return topic_model_list
with self.driver.session() as session:
return session.execute_read(get_topics_work)
# implemented
def get_topic(self, project_id: UUID, topic_id: UUID, current_user: User) -> TopicGET:
def get_topic_work(tx) -> TopicGET:
cypher = """
MATCH (u:User)-[r1:HAS_ACTIONS_ON]->(p:Project)-[r2:HAS]->(t:Topic)
WHERE u.username = $username
AND r1.read = True
AND p.project_id = $project_id
AND t.guid = $topic_id
RETURN t AS topic, ID(t) AS server_assigned_id
"""
result = tx.run(cypher,
username=current_user.username,
project_id=str(project_id),
topic_id=str(topic_id))
first = result.single()
if first is None:
raise HTTPException(status_code=404, detail="Item not found.")
topic_node = first.get("topic")
topic_dict = self.node_to_json(topic_node)
topic_dict["server_assigned_id"] = first.get("server_assigned_id")
return TopicGET(**topic_dict)
with self.driver.session() as session:
return session.execute_read(get_topic_work)
# implemented
def post_topic(self, project_id: UUID, topic: TopicPOST, current_user: User) -> TopicGET:
def post_topic_work(tx) -> UUID:
cypher = """
MATCH (u:User)-[r1:HAS_ACTIONS_ON]->(p:Project)
WHERE u.username = $username
AND r1.createTopic = True
AND p.project_id = $project_id
MERGE (p)-[r2:HAS]->(t:Topic {guid: $guid})
SET t.creation_date = $creation_date,
t.modified_date = $creation_date,
t.creation_author = $username,
t.modified_author = $username,
t.topic_type = $topic_type,
t.topic_status = $topic_status,
t.title = $title,
t.priority = $priority,
t.index = $index,
t.assigned_to = $assigned_to,
t.stage = $stage,
t.description = $description,
t.due_date = $due_date
RETURN t AS topic, ID(t) AS server_assigned_id
"""
if not hasattr(topic, 'guid') or topic.guid is None:
topic.guid = uuid4()
creation_date = self.timestamp()
print(cypher)
result = tx.run(cypher,
username=current_user.username,
project_id=str(project_id),
guid=str(topic.guid),
creation_date=creation_date,
topic_type=topic.topic_type,
topic_status=topic.topic_status,
title=topic.title,
priority=topic.priority,
index=topic.index,
assigned_to=topic.assigned_to,
stage=topic.stage,
description=topic.description,
due_date=topic.due_date)
summary = result.consume()
if summary.counters.nodes_created < 1:
raise HTTPException(status_code=400, detail="Item not added.")
return topic.guid
with self.driver.session() as session:
topic_guid = session.execute_write(post_topic_work)
return self.get_topic(project_id, topic_guid, current_user)
# implemented
def put_topic(self, project_id: UUID, topic_id: UUID, topic: TopicPUT, current_user: User) -> TopicGET:
def put_topic_work(tx) -> bool:
cypher = """
MATCH (u:User)-[r1:HAS_ACTIONS_ON]->(p:Project)-[r2:HAS]->(t:Topic)
WHERE u.username = $username
AND r1.update = True
AND p.project_id = $project_id
AND t.guid = $topic_id
SET t.topic_type = $topic_type,
t.topic_status = $topic_status,
t.title = $title,
t.priority = $priority,
t.index = $index,
t.modified_date = $modified_date,
t.modified_author = $username,
t.assigned_to = $assigned_to,
t.stage = $stage,
t.description = $description,
t.due_date = $due_date
RETURN t AS topic, ID(t) AS server_assigned_id
"""
result = tx.run(cypher,
username=current_user.username,
project_id=str(project_id),
topic_id=str(topic_id),
topic_type=topic.topic_type,
topic_status=topic.topic_status,
title=topic.title,
priority=topic.priority,
index=topic.index,
modified_date=self.timestamp(),
assigned_to=topic.assigned_to,
stage=topic.stage,
description=topic.description,
due_date=topic.due_date)
summary = result.consume()
if summary.counters.properties_set < 1:
raise HTTPException(status_code=404, detail="Item not found.")
return True
with self.driver.session() as session:
session.execute_write(put_topic_work)
return self.get_topic(project_id, topic_id, current_user)
# implemented
def set_topic_modified_date(self, project_id: UUID, topic_id: UUID, current_user: User) -> bool:
def set_topic_modified_date_work(tx) -> bool:
cypher = """
MATCH (u:User)-[r1:HAS_ACTIONS_ON]->(p:Project)-[r2:HAS]->(t:Topic)
WHERE u.username = $username
AND r1.update = True
AND p.project_id = $project_id
AND t.guid = $topic_id
SET t.modified_date = $modified_date
"""
result = tx.run(cypher,
username=current_user.username,
project_id=str(project_id),
topic_id=str(topic_id),
modified_date=self.timestamp())
summary = result.consume()
if summary.counters.properties_set < 1:
raise HTTPException(status_code=404, detail="Item not found.")
return True
with self.driver.session() as session:
return session.execute_write(set_topic_modified_date_work)
# implemented
def delete_topic(self, project_id: UUID, topic_id: UUID, current_user: User) -> int:
def delete_topic_work(tx) -> int:
cypher = """
MATCH (u:User)-[r1:HAS_ACTIONS_ON]->(p:Project)-[r2:HAS]->(t:Topic)
WHERE u.username = $username
AND r1.update = True
AND p.project_id = $project_id
AND t.guid = $topic_id
DETACH DELETE t
"""
result = tx.run(cypher,
username=current_user.username,
project_id=str(project_id),
topic_id=str(topic_id))
result_summary = result.consume()
if result_summary.counters.nodes_deleted < 1:
raise HTTPException(status_code=404, detail="Item not found.")
return result_summary.counters.nodes_deleted
with self.driver.session() as session:
return session.execute_write(delete_topic_work)
# implemented
# returns a collection
def get_files_information(self, project_id: UUID, current_user: User) -> List[ProjectFileInformation]:
def get_files_information_work(tx) -> List[ProjectFileInformation]:
cypher = """
MATCH (u:User)-[r1:HAS_ACTIONS_ON]->(p:Project)-[r2:CONTAINS]->(d:Document)
WHERE u.username = $username
AND r1.read = True
AND p.project_id = $project_id
RETURN d AS document
"""
results = tx.run(cypher,
username=current_user.username,
project_id=str(project_id))
project_file_informations = list()
for result in results:
document_json = self.node_to_json(result.get("document"))
display_information_list = list()
display_information_json = {
'field_display_name': 'File',
'field_value': document_json['title']
}
display_information_list.append(display_information_json)
base = os.environ['KONTROLL_BASE_URL'] + "documents/1.0/document/"
base.replace('http://', 'https://')
base.replace('https://', 'open-cde-documents://')
document_id = document_json['document_id']
version_index = document_json['version_index']
extra_path = document_id + "/version/" + str(version_index)
reference = base + extra_path
file_get_json = {
'ifc_project': document_json['ifc_project'],
'filename': document_json['name'],
'reference': reference
}
project_file_information = ProjectFileInformation(**{
'display_information': display_information_list,
'file': file_get_json
})
project_file_informations.append(project_file_information)
return project_file_informations
#
# BCF API compatible servers offer endpoints to list project model files, which are stored on a CDE.
# To indicate that models provided by BCF API file-references can be downloaded from the CDE using
# the Documents API, the reference part of a file_GET response from the BCF server will include
# the URL scheme (protocol) open-cde-documents and a link to the document_version URL on the CDE.
#
# The actual URL scheme (protocol) that a Client Application should
# use to call the document_version URL should be https.
#
# BCF API project_file_information example:
#
# {
# "display_information": [
# {
# "field_display_name": "Model Name",
# "field_value": "ARCH-Z100-051"
# }
# ],
# "file": {
# "ifc_project": "0J$yPqHBD12v72y4qF6XcD",
# "file_name": "OfficeBuilding_Architecture_0001.ifc",
# "reference": "open-cde-documents://<document_version_url>"
# }
# }
#
# In the example above, the CDE returns a value of
# open-cde-documents://<document_version_url> for the file reference part,
# indicating that a Documents API capable client can call https://<document_version_url>
# to get the document version information. From there on, compatible
# clients can retrieve metadata and the binary content of the file.
#
# class ProjectFileInformation(BaseModel):
# display_information: Optional[List[ProjectFileDisplayInformation]] = None
# file: Optional[FileGET] = None
#
# class ProjectFileDisplayInformation(BaseModel):
# field_display_name: str
# field_value: str
#
# class FileGET(BaseModel):
# ifc_project: Optional[str] = None
# ifc_spatial_structure_element: Optional[str] = None
# filename: Optional[str] = None
# date: Optional[str] = None
# reference: Optional[str] = None
#
with self.driver.session() as session:
return session.execute_read(get_files_information_work)
# implemented
# returns a collection
def get_files(self, project_id: UUID, topic_id: UUID, current_user: User) -> List[FileGET]:
def get_files_work(tx) -> List[FileGET]:
cypher = """
MATCH (u:User)-[r1:HAS_ACTIONS_ON]->(p:Project)-[r2:HAS]->(t:Topic)-[r3:REFERS_TO]->(f:Document:Model)
WHERE u.username = $username
AND r1.read = True
AND p.project_id = $project_id
AND t.guid = $topic_id
RETURN f AS file
"""
results = tx.run(cypher,
username=current_user.username,
project_id=str(project_id),
topic_id=str(topic_id))
file_model_list = list()
for result in results:
file_json = self.node_to_json(result.get("file"))
file_model = FileGET(**file_json)
file_model_list.append(file_model)
return file_model_list
with self.driver.session() as session:
return session.execute_read(get_files_work)
# implemented
def put_files(self, project_id: UUID, topic_id: UUID, files: List[FilePUT], current_user: User) -> List[FileGET]:
def put_files_work(tx) -> bool:
cypher_delete_references = """
MATCH (u:User)-[r1:HAS_ACTIONS_ON]->(p:Project)-[r2:HAS]->(t:Topic)-[r3:REFERS_TO]->(f:Document:Model)
WHERE u.username = $username
AND r1.updateFiles = True
AND p.project_id = $project_id
AND t.guid = $topic_id
DELETE r3
"""
tx.run(cypher_delete_references,
username=current_user.username,
project_id=str(project_id),
topic_id=str(topic_id))
cypher_update_and_attach_references = """
MATCH (u:User)-[r1:HAS_ACTIONS_ON]->(p:Project)-[r2:HAS]->(f:Document:Model)
MATCH (u)-[r1]->(p)-[r3:HAS]->(t:Topic)
WHERE u.username = $username
AND r1.updateFiles = True
AND p.project_id = $project_id
AND f.reference = $reference
AND t.guid = $topic_id
SET f.filename = $filename,
f.date = $date,
f.ifc_project = $ifc_project,
f.ifc_spatial_structure_element = $ifc_spatial_structure_element
MERGE (t)-[r4:REFERS_TO]->(f)
RETURN f
"""
for file in files:
result = tx.run(cypher_update_and_attach_references,
username=current_user.username,
project_id=str(project_id),
reference=file.reference,
topic_id=str(topic_id),
filename=file.filename,
date=file.date,
ifc_project=file.ifc_project,
ifc_spatial_structure_element=file.ifc_spatial_structure_element)
first = result.single()
if first is None:
raise HTTPException(status_code=404, detail="Item not found.")
return True
with self.driver.session() as session:
session.execute_write(put_files_work)
return self.get_files(project_id, topic_id, current_user)
# implemented
def get_comments(self, project_id: UUID, topic_id: UUID, current_user: User) -> List[CommentGET]:
def get_comments_work(tx) -> List[CommentGET]:
cypher = """
MATCH (u:User)-[r1:HAS_ACTIONS_ON]->(p:Project)-[r2:HAS]->(t:Topic)-[r3:HAS]->(c:Comment)
WHERE u.username = $username
AND r1.read = True
AND p.project_id = $project_id
AND t.guid = $topic_id
RETURN c AS comment
"""
results = tx.run(cypher,
username=current_user.username,
project_id=str(project_id),
topic_id=str(topic_id))
comment_model_list = list()
for result in results:
comment_json = self.node_to_json(result.get("comment"))
comment_json['topic_guid'] = str(topic_id)
comment_model = CommentGET(**comment_json)
comment_model_list.append(comment_model)
return comment_model_list
with self.driver.session() as session:
return session.execute_read(get_comments_work)
# implemented
def get_comment(self, project_id: UUID, topic_id: UUID, comment_id: UUID, current_user: User) -> CommentGET:
def get_comment_work(tx) -> CommentGET:
cypher = """
MATCH (u:User)-[r1:HAS_ACTIONS_ON]->(p:Project)-[r2:HAS]->(t:Topic)-[r3:HAS]->(c:Comment)
WHERE u.username = $username
AND r1.read = True
AND p.project_id = $project_id
AND t.guid = $topic_id
AND c.guid = $comment_id
RETURN c AS comment
"""
result = tx.run(cypher,
username=current_user.username,
project_id=str(project_id),
topic_id=str(topic_id),
comment_id=str(comment_id))
first = result.single()
if first is None:
raise HTTPException(status_code=404, detail="Item not found.")
comment_node = first.get("comment")
comment_dict = self.node_to_json(comment_node)
comment_dict['topic_guid'] = str(topic_id)
comment = CommentGET(**comment_dict)
return comment
with self.driver.session() as session:
return session.execute_read(get_comment_work)
# date
# author
# topic_guid
def post_comment(self, project_id: UUID, topic_id: UUID, comment: CommentPOST, current_user: User) -> CommentGET:
def post_comment_work(tx) -> UUID:
if not hasattr(comment, 'guid') or comment.guid is None:
this_comment_guid = uuid4()
else:
this_comment_guid = UUID(comment.guid)
if comment.viewpoint_guid:
# make sure that given viewpoint_guid exists in database
viewpoints = self.get_viewpoints(project_id, topic_id, current_user)
viewpoint_guids = [viewpoint.guid for viewpoint in viewpoints]
if comment.viewpoint_guid not in viewpoint_guids:
raise HTTPException(status_code=400, detail="Item not added.")
injection_viewpoint = '-[r3:HAS]->(v:Viewpoint)'
injection_viewpoint_selection = 'AND v.guid = $viewpoint_id'
injection_viewpoint_relation = 'MERGE (c2)-[r7:RELATED_TO]->(v)'
else:
injection_viewpoint = ''
injection_viewpoint_selection = ''
injection_viewpoint_relation = ''
if hasattr(comment, 'reply_to_comment_guid'):
# make sure that given reply_to_comment_guid exists in database
get_comments = self.get_comments(project_id, topic_id, current_user)
comment_guids = [get_comment.guid for get_comment in get_comments]
if comment.reply_to_comment_guid not in comment_guids:
raise HTTPException(status_code=400, detail="Item not added.")
injection_existing_comment = 'MATCH (u)-[r1]->(p)-[r2]->(t)-[r4:HAS]->(c1:Comment)'
injection_existing_comment_selection = 'AND c1.guid = $reply_to_comment_id'
injection_existing_comment_relation = 'MERGE (c1)-[r5:THEN]->(c2)'
else:
injection_existing_comment = ''
injection_existing_comment_selection = ''
injection_existing_comment_relation = ''
cypher = """
MATCH (u:User)-[r1:HAS_ACTIONS_ON]->(p:Project)-[r2:HAS]->(t:Topic)%s
%s
WHERE u.username = $username
AND r1.createComment = True
AND p.project_id = $project_id
AND t.guid = $topic_id
%s
%s
MERGE (t)-[r5:HAS]->(c2:Comment {guid: $comment_id})
%s
%s
SET c2.date = $creation_date,
c2.modified_date = $creation_date,
c2.author = $username,
c2.modified_author = $username,
c2.comment = $comment
""" % (injection_viewpoint,
injection_existing_comment,
injection_viewpoint_selection,
injection_existing_comment_selection,
injection_viewpoint_relation,
injection_existing_comment_relation)
result = tx.run(cypher,
username=current_user.username,
project_id=str(project_id),
topic_id=str(topic_id),
viewpoint_id=str(comment.viewpoint_guid),
reply_to_comment_id=str('comment.reply_to_comment_guid'),
comment_id=str(this_comment_guid),
creation_date=self.timestamp(),
comment=comment.comment)
summary = result.consume()
if summary.counters.nodes_created < 1:
raise HTTPException(status_code=400, detail="Item not added.")
return this_comment_guid
with self.driver.session() as session:
comment_guid = session.execute_write(post_comment_work)
return self.get_comment(project_id, topic_id, comment_guid, current_user)
def put_comment(self, project_id: UUID, topic_id: UUID, comment_id: UUID, comment: CommentPUT,
current_user: User) -> CommentGET:
def put_comment_work(tx) -> bool:
if comment.viewpoint_guid:
viewpoints = self.get_viewpoints(project_id, topic_id, current_user)
viewpoint_guids = [viewpoint.guid for viewpoint in viewpoints]
if comment.viewpoint_guid not in viewpoint_guids:
raise HTTPException(status_code=400, detail="Item not added.")
injection_new_viewpoint = 'MATCH (t)-[r5:HAS]->(v_new:Viewpoint)'
injection_new_viewpoint_selection = 'WHERE v_new.guid = $new_rtv_id'
injection_new_viewpoint_relation = 'MERGE (c)-[r5:RELATED_TO]->(v)'
else:
injection_new_viewpoint = ''
injection_new_viewpoint_selection = ''
injection_new_viewpoint_relation = ''
cypher = """
MATCH (u:User)-[r1:HAS_ACTIONS_ON]->(p:Project)-[r2:HAS]->(t:Topic)-[r3:HAS]->(c:Comment)
WHERE u.username = $username
AND r1.updateComment = True
AND p.project_id = $project_id
AND t.guid = $topic_id
AND c.guid = $comment_id
OPTIONAL MATCH (c)-[r4:RELATED_TO]->(v_existing:Viewpoint)
%s
%s
SET c.comment = $comment
SET c.modified_date = $modified_date
SET c.modified_author = $username
DELETE r4
%s
""" % (injection_new_viewpoint,
injection_new_viewpoint_selection,
injection_new_viewpoint_relation)
result = tx.run(cypher,
username=current_user.username,
project_id=str(project_id),
topic_id=str(topic_id),
comment_id=str(comment_id),
new_rtv_id=str(comment.viewpoint_guid),
comment=comment.comment,
modified_date=self.timestamp())
summary = result.consume()
if summary.counters.properties_set < 1:
raise HTTPException(status_code=400, detail="Item not added.")
return True
with self.driver.session() as session:
session.execute_write(put_comment_work)
return self.get_comment(project_id, topic_id, comment_id, current_user)
# implemented
def delete_comment(self, project_id: UUID, topic_id: UUID, comment_id: UUID, current_user: User) -> int:
def delete_comment_work(tx) -> int:
cypher = """
MATCH (u:User)-[r1:HAS_ACTIONS_ON]->(p:Project)-[r2:HAS]->(t:Topic)-[r3:HAS]->(c:Comment)
WHERE u.username = $username
AND r1.update = True
AND p.project_id = $project_id
AND t.guid = $topic_id
AND c.guid = $comment_id
DETACH DELETE c
"""
result = tx.run(cypher,
username=current_user.username,
project_id=str(project_id),
topic_id=str(topic_id),
comment_id=str(comment_id))
result_summary = result.consume()
if result_summary.counters.nodes_deleted < 1:
raise HTTPException(status_code=404, detail="Item not found.")
return result_summary.counters.nodes_deleted
with self.driver.session() as session:
self.set_topic_modified_date(project_id, topic_id, current_user)
return session.execute_write(delete_comment_work)
@staticmethod
def enum_to_mime(enum_type) -> str:
if str(enum_type) == 'png':
mime_type = 'image/png'
elif str(enum_type) == 'jpg' or str(enum_type) == 'jpeg':
mime_type = 'image/jpeg'
else:
mime_type = 'image/' + str(enum_type)
return mime_type
# implementing
def post_viewpoint(self, project_id: UUID, topic_id: UUID, viewpoint: ViewpointPOST,
current_user: User) -> ViewpointGET:
def post_viewpoint_work(tx) -> str:
if hasattr(viewpoint, 'snapshot'):
snapshot_type = self.enum_to_mime(viewpoint.snapshot.snapshot_type.value)
snapshot = True
set_snapshot = 'v.snapshot = $snapshot, v.snapshot_type = $snapshot_type,'
else:
snapshot_type = ''
snapshot = False
set_snapshot = ''
cypher_viewpoint = """
MATCH (u:User)-[r1:HAS_ACTIONS_ON]->(p:Project)-[r2:HAS]->(t:Topic)
WHERE u.username = $username
AND r1.createViewpoint = True
AND p.project_id = $project_id
AND t.guid = $topic_id
MERGE (t)-[r3:HAS]->(v:Viewpoint {guid: $guid, index: $index})
SET v.camera_definition = $camera_definition,
v.camera_view_point = point({x: $cvp_x, y: $cvp_y, z: $cvp_z}),
v.camera_direction = point({x: $cad_x, y: $cad_y, z: $cad_z}),
v.camera_up_vector = point({x: $cuv_x, y: $cuv_y, z: $cuv_z}),
v.view_tws_or_fo_view = $view_tws_or_fo_view,
v.aspect_ratio = $aspect_ratio,
%s
v.default_visibility = $default_visibility,
v.spaces_visible = $spaces_visible,
v.space_boundaries_visible = $space_boundaries_visible,
v.openings_visible = $openings_visible
""" % set_snapshot
if viewpoint.guid is None:
viewpoint.guid = uuid4()
if viewpoint.orthogonal_camera is None:
camera_definition = 'perspective_camera'
view_tws_or_fo_view = viewpoint.perspective_camera.field_of_view
aspect_ratio = viewpoint.perspective_camera.aspect_ratio
cvp = viewpoint.perspective_camera.camera_view_point
cad = viewpoint.perspective_camera.camera_direction
cuv = viewpoint.perspective_camera.camera_up_vector
else:
camera_definition = 'orthogonal_camera'
view_tws_or_fo_view = viewpoint.orthogonal_camera.view_to_world_scale
aspect_ratio = viewpoint.orthogonal_camera.aspect_ratio
cvp = viewpoint.orthogonal_camera.camera_view_point
cad = viewpoint.orthogonal_camera.camera_direction
cuv = viewpoint.orthogonal_camera.camera_up_vector
result = tx.run(cypher_viewpoint,
username=current_user.username,
project_id=str(project_id),
topic_id=str(topic_id),
guid=str(viewpoint.guid),
index=viewpoint.index,
camera_definition=camera_definition,
cvp_x=cvp.x, cvp_y=cvp.y, cvp_z=cvp.z,
cad_x=cad.x, cad_y=cad.y, cad_z=cad.z,
cuv_x=cuv.x, cuv_y=cuv.y, cuv_z=cuv.z,
view_tws_or_fo_view=view_tws_or_fo_view,
aspect_ratio=aspect_ratio,
snapshot=snapshot,
snapshot_type=snapshot_type,
default_visibility=viewpoint.components.visibility.default_visibility,
spaces_visible=viewpoint.components.visibility.view_setup_hints.spaces_visible,
space_boundaries_visible=viewpoint.components.visibility.view_setup_hints.space_boundaries_visible,
openings_visible=viewpoint.components.visibility.view_setup_hints.openings_visible)
summary = result.consume()
if summary.counters.nodes_created < 1:
print(cypher_viewpoint)
raise HTTPException(status_code=400, detail="Item not added.")
# LINES
for line in viewpoint.lines:
cypher_line = """
MATCH (v:Viewpoint)
WHERE v.guid = $guid
MERGE (v)-[r1:HAS]->(l:Line)
SET l.start_point = point({x: $lsp_x, y: $lsp_y, z: $lsp_z}),
l.end_point = point({x: $lep_x, y: $lep_y, z: $lep_z})
"""
result = tx.run(cypher_line,
guid=str(viewpoint.guid),
lsp_x=line.start_point.x, lsp_y=line.start_point.y, lsp_z=line.start_point.z,
lep_x=line.end_point.x, lep_y=line.end_point.y, lep_z=line.end_point.z)
summary = result.consume()
if summary.counters.nodes_created < 1:
print(cypher_line)
raise HTTPException(status_code=400, detail="Item not added.")
# CLIPPING PLANES
for clipping_plane in viewpoint.clipping_planes:
cypher_clipping_plane = """
MATCH (v:Viewpoint)
WHERE v.guid = $guid
MERGE (v)-[r1:HAS]->(cp:ClippingPlane)
SET cp.location = point({x: $cpl_x, y: $cpl_y, z: $cpl_z}),
cp.direction = point({x: $cpd_x, y: $cpd_y, z: $cpd_z})
"""
result = tx.run(cypher_clipping_plane,
guid=str(viewpoint.guid),
lsp_x=clipping_plane.location.x, lsp_y=clipping_plane.location.y,
lsp_z=clipping_plane.location.z,
lep_x=clipping_plane.direction.x, lep_y=clipping_plane.direction.y,
lep_z=clipping_plane.direction.z)
summary = result.consume()
if summary.counters.nodes_created < 1:
print(cypher_clipping_plane)
raise HTTPException(status_code=400, detail="Item not added.")
# BITMAPS
for bitmap in viewpoint.bitmaps:
cypher_bitmap = """
MATCH (v:Viewpoint)
WHERE v.guid = $guid
MERGE (v)-[r1:HAS]->(b:Bitmap)
SET b.type = $type,
b.location = point({x: $bml_x, y: $bml_y, z: $bml_z}),
b.normal = point({x: $bmn_x, y: $bmn_y, z: $bmn_z}),
b.up = point({x: $bmu_x, y: $bmu_y, z: $bmu_z}),
b.height = $height
"""
bitmap_type = self.enum_to_mime(bitmap.bitmap_type)
result = tx.run(cypher_bitmap,
guid=str(viewpoint.guid),
type=bitmap_type,
bml_x=bitmap.location.x, bml_y=bitmap.location.y, bml_z=bitmap.location.z,
bmn_x=bitmap.direction.x, bmn_y=bitmap.direction.y, bmn_z=bitmap.direction.z,
bmu_x=bitmap.direction.x, bmu_y=bitmap.direction.y, bmu_z=bitmap.direction.z,
height=bitmap.height)
summary = result.consume()
if summary.counters.nodes_created < 1:
print(bitmap_type)
raise HTTPException(status_code=400, detail="Item not added.")
# COMPONENTS
components = {}
for selected_component in viewpoint.components.selection:
if selected_component.ifc_guid not in components:
components[selected_component.ifc_guid] = {}
components[selected_component.ifc_guid]['selected'] = True
components[selected_component.ifc_guid]['originating_system'] = selected_component.originating_system
components[selected_component.ifc_guid]['authoring_tool_id'] = selected_component.authoring_tool_id
for color in viewpoint.components.coloring:
for colored_component in color.components:
if colored_component.ifc_guid not in components:
components[colored_component.ifc_guid] = {}
components[colored_component.ifc_guid]['color'] = color.color
for exception_component in viewpoint.components.visibility.exceptions:
if exception_component.ifc_guid not in components:
components[exception_component.ifc_guid] = {}
components[exception_component.ifc_guid]['visibility_exception'] = True
set_list = list()
for ifc_guid in components.keys():
set_list.append('c.ifc_guid = $ifc_guid')
if 'selected' in components[ifc_guid]:
selected = True
originating_system = components[ifc_guid]['originating_system']
authoring_tool_id = components[ifc_guid]['authoring_tool_id']
set_list.append('c.selected = $selected')
set_list.append('c.originating_system = $originating_system')
set_list.append('c.authoring_tool_id = $authoring_tool_id')
else:
selected = False
originating_system = False
authoring_tool_id = False
if 'color' in components[ifc_guid]:
color = components[ifc_guid]['color']
set_list.append('c.color = $color')
else:
color = False
if 'visibility_exception' in components[ifc_guid]:
visibility_exception = True
set_list.append('c.visibility_exception = $visibility_exception')
else:
visibility_exception = False
set_string = ', '.join(set_list)
cypher_component = """
MATCH (v:Viewpoint)
WHERE v.guid = $viewpoint_id
MERGE (v)-[r1:HAS]->(c:Component {ifc_guid: $ifc_guid})
SET
"""
cypher_component += set_string
tx.run(cypher_component,
viewpoint_id=str(viewpoint.guid),
ifc_guid=str(ifc_guid),
selected=selected,
originating_system=originating_system,
authoring_tool_id=authoring_tool_id,
color=color,
visibility_exception=visibility_exception)
summary = result.consume()
# Look for component UUIDs in IFC-graph and relate them
for ifc_guid in components.keys():
cypher_link = """
MATCH (prod:IfcProduct) WHERE prod.GlobalId = $uuid
MATCH (c:Component) WHERE c.ifc_guid = $uuid
MERGE (c)-[r:SAME_AS]->(prod)
"""
tx.run(cypher_link, uuid=str(ifc_guid))
result.consume()
cypher_link = """
MATCH (prod:IfcProduct)
-[r1:IsDefinedBy]->(rs:IfcRelationship)
-[r2:RelatingPropertyDefinition]->(ps:IfcPropertySet)
-[r3:HasProperties]->(prop:IfcProperty)
-[r4:NominalValue]->(root:Root)
WHERE prod.GlobalId = $uuid
AND ps.Name = 'Reuse'
AND prop.Name = 'GTIN'
MATCH (c:Component) WHERE c.ifc_guid = $uuid
SET c.GTIN = root.wrappedValue
"""
tx.run(cypher_link, uuid=str(ifc_guid))
result.consume()
if summary.counters.nodes_created < 1:
print(cypher_component)
raise HTTPException(status_code=400, detail="Item not added.")
else:
snapshot_path = ''
bitmap_path = ''
try:
snapshot_name = 'snapshot_' + str(viewpoint.guid)
file_ending = '.' + str(viewpoint.snapshot.snapshot_type.value)
snapshot_path = 'data/snapshots/' + snapshot_name + file_ending
with open(snapshot_path, "wb") as snapshot_file:
snapshot_image = base64.b64decode(viewpoint.snapshot.snapshot_data, validate=True)
snapshot_file.write(snapshot_image)
snapshot_file.close()
for bitmap in viewpoint.bitmaps:
bitmap_name = 'bitmap_' + str(bitmap.guid)
file_ending = '.' + str(bitmap.bitmap_type.value)
bitmap_path = 'data/bitmaps/' + bitmap_name + file_ending
with open(bitmap_path, "wb") as bitmap_file:
bitmap_image = base64.b64decode(bitmap.bitmap_data, validate=True)
bitmap_file.write(bitmap_image)
bitmap_file.close()
except Exception as e:
print('could not create file ' + snapshot_path + ' ' + bitmap_path + ' ')
print(e)
raise HTTPException(status_code=400, detail="Item not added.")
return viewpoint.guid
with self.driver.session() as session:
viewpoint.guid = session.execute_write(post_viewpoint_work)
viewpoint.guid = UUID(viewpoint.guid)
self.set_topic_modified_date(project_id, topic_id, current_user)
return self.get_viewpoint(project_id, topic_id, viewpoint.guid, current_user)
# implemented
# returns a collection
def get_viewpoints(self, project_id: UUID, topic_id: UUID, current_user: User) -> List[ViewpointGET]:
def get_viewpoints_work(tx) -> List[ViewpointGET]:
cypher = """
MATCH (u:User)-[r1:HAS_ACTIONS_ON]->(p:Project)-[r2:HAS]->(t:Topic)-[r3:HAS]->(v:Viewpoint)
WHERE u.username = $username
AND r1.read = True
AND p.project_id = $project_id
AND t.guid = $topic_id
RETURN v.guid AS viewpoint_id
"""
results = tx.run(cypher,
username=current_user.username,
project_id=str(project_id),
topic_id=str(topic_id))
viewpoint_model_list = list()
for result in results:
viewpoint_id = result.get("viewpoint_id")
viewpoint_model = self.get_viewpoint(project_id, topic_id, viewpoint_id, current_user)
viewpoint_model_list.append(viewpoint_model)
return viewpoint_model_list
with self.driver.session() as session:
return session.execute_read(get_viewpoints_work)
# pending
def get_viewpoint(self, project_id: UUID, topic_id: UUID, viewpoint_id: UUID, current_user: User) -> ViewpointGET:
def get_viewpoint_work(tx) -> ViewpointGET:
cypher = """
MATCH (u:User)-[r1:HAS_ACTIONS_ON]->(p:Project)-[r2:HAS]->(t:Topic)-[r3:HAS]->(v:Viewpoint)
WHERE u.username = $username
AND r1.read = True
AND p.project_id = $project_id
AND t.guid = $topic_id
AND v.guid = $viewpoint_id
RETURN v AS viewpoint
"""
result = tx.run(cypher,
username=current_user.username,
project_id=str(project_id),
topic_id=str(topic_id),
viewpoint_id=str(viewpoint_id))
first = result.single()
if first is None:
raise HTTPException(status_code=404, detail="Item not found.")
v_node = first.get("viewpoint")
print(v_node)
v = self.node_to_json(v_node)
print(v)
lines = self.get_viewpoint_lines(project_id, topic_id, viewpoint_id, current_user)
clipping_planes = self.get_viewpoint_clipping_planes(project_id, topic_id, viewpoint_id, current_user)
bitmaps = self.get_viewpoint_bitmaps(project_id, topic_id, viewpoint_id, current_user)
snapshot_get = {
'snapshot_type': v['snapshot_type'].split('/', 2)[1]
}
viewpoint_get = {
'guid': v['guid'],
'index': v['index'],
'lines': lines,
'clipping_planes': clipping_planes,
'bitmaps': bitmaps,
'snapshot': snapshot_get
}
cvp = v['camera_view_point']
cad = v['camera_direction']
cuv = v['camera_up_vector']
camera = {
'camera_view_point': {'x': cvp.x, 'y': cvp.y, 'z': cvp.z},
'camera_direction': {'x': cad.x, 'y': cad.y, 'z': cad.z},
'camera_up_vector': {'x': cuv.x, 'y': cuv.y, 'z': cuv.z},
'aspect_ratio': v['aspect_ratio']
}
if v['camera_definition'] == 'orthogonal_camera':
camera['view_to_world_scale'] = v['view_tws_or_fo_view']
viewpoint_get['orthogonal_camera'] = camera
elif v['camera_definition'] == 'perspective_camera':
camera['field_of_view'] = v['view_tws_or_fo_view']
viewpoint_get['perspective_camera'] = camera
jsonpickle.dumps(v)
jsonpickle.dumps(viewpoint_get)
return ViewpointGET(**viewpoint_get)
with self.driver.session() as session:
return session.execute_read(get_viewpoint_work)
def get_viewpoint_lines(self, project_id: UUID, topic_id: UUID, viewpoint_id: UUID,
current_user: User) -> List[Line]:
def get_viewpoint_lines_work(tx) -> List[Line]:
cypher = """
MATCH (u:User)-[r1:HAS_ACTIONS_ON]->(p:Project)-[r2:HAS]->(t:Topic)-[r3:HAS]->(v:Viewpoint)-[r4:HAS]->(l:Line)
WHERE u.username = $username
AND r1.read = True
AND p.project_id = $project_id
AND t.guid = $topic_id
AND v.guid = $viewpoint_id
RETURN l AS line
"""
results = tx.run(cypher,
username=current_user.username,
project_id=str(project_id),
topic_id=str(topic_id),
viewpoint_id=str(viewpoint_id))
line_model_list = list()
for result in results:
line_node = result.get("line")
line_json = {
'start_point': line_node.start_point,
'end_point': line_node.end_point
}
line_model = Line(**line_json)
line_model_list.append(line_model)
return line_model_list
with self.driver.session() as session:
return session.execute_read(get_viewpoint_lines_work)
def get_viewpoint_clipping_planes(self, project_id: UUID, topic_id: UUID, viewpoint_id: UUID,
current_user: User) -> List[ClippingPlane]:
def get_viewpoint_clipping_planes_work(tx) -> List[ClippingPlane]:
cypher = """
MATCH (u:User)-[r1:HAS_ACTIONS_ON]->(p:Project)-[r2:HAS]->(t:Topic)-[r3:HAS]->(v:Viewpoint)-[r4:HAS]->(cp:ClippingPlane)
WHERE u.username = $username
AND r1.read = True
AND p.project_id = $project_id
AND t.guid = $topic_id
AND v.guid = $viewpoint_id
RETURN cp AS clipping_plane
"""
results = tx.run(cypher,
username=current_user.username,
project_id=str(project_id),
topic_id=str(topic_id),
viewpoint_id=str(viewpoint_id))
clipping_plane_model_list = list()
for result in results:
clipping_plane_json = self.node_to_json(result.get("clipping_plane"))
clipping_plane_model = ClippingPlane(**clipping_plane_json)
clipping_plane_model_list.append(clipping_plane_model)
return clipping_plane_model_list
with self.driver.session() as session:
return session.execute_read(get_viewpoint_clipping_planes_work)
def get_viewpoint_bitmaps(self, project_id: UUID, topic_id: UUID, viewpoint_id: UUID,
current_user: User) -> List[BitmapGET]:
def get_viewpoint_bitmaps_work(tx) -> List[BitmapGET]:
cypher = """
MATCH (u:User)-[r1:HAS_ACTIONS_ON]->(p:Project)-[r2:HAS]->(t:Topic)-[r3:HAS]->(v:Viewpoint)-[r4:HAS]->(b:Bitmap)
WHERE u.username = $username
AND r1.read = True
AND p.project_id = $project_id
AND t.guid = $topic_id
AND v.guid = $viewpoint_id
RETURN b AS bitmap
"""
results = tx.run(cypher,
username=current_user.username,
project_id=str(project_id),
topic_id=str(topic_id),
viewpoint_id=str(viewpoint_id))
bitmap_model_list = list()
for result in results:
bitmap_json = self.node_to_json(result.get("bitmap"))
bitmap_model = BitmapGET(**bitmap_json)
bitmap_model_list.append(bitmap_model)
return bitmap_model_list
with self.driver.session() as session:
return session.execute_read(get_viewpoint_bitmaps_work)
def get_viewpoint_bitmap(self, project_id: UUID, topic_id: UUID, viewpoint_id: UUID, bitmap_id: UUID,
current_user: User) -> BitmapGET:
def get_viewpoint_bitmap_work(tx) -> BitmapGET:
cypher = """
MATCH (u:User)-[r1:HAS_ACTIONS_ON]->(p:Project)-[r2:HAS]->(t:Topic)-[r3:HAS]->(v:Viewpoint)-[r4:HAS]->(b:Bitmap)
WHERE u.username = $username
AND r1.read = True
AND p.project_id = $project_id
AND t.guid = $topic_id
AND v.guid = $viewpoint_id
AND b.guid = $bitmap_id
RETURN b AS bitmap
"""
result = tx.run(cypher,
username=current_user.username,
project_id=str(project_id),
topic_id=str(topic_id),
viewpoint_id=str(viewpoint_id),
bitmap_id=str(bitmap_id))
bitmap_json = self.node_to_json(result.get("bitmap"))
return BitmapGET(**bitmap_json)
with self.driver.session() as session:
return session.execute_read(get_viewpoint_bitmap_work)
def get_viewpoint_snapshot(self, project_id: UUID, topic_id: UUID, viewpoint_id: UUID, current_user: User) -> str:
def get_viewpoint_snapshot_work(tx) -> str:
cypher = """
MATCH (u:User)-[r1:HAS_ACTIONS_ON]->(p:Project)-[r2:HAS]->(t:Topic)-[r3:HAS]->(v:Viewpoint)
WHERE u.username = $username
AND r1.read = True
AND p.project_id = $project_id
AND t.guid = $topic_id
AND v.guid = $viewpoint_id
AND v.snapshot IS NOT NULL
RETURN v.snapshot_type AS snapshot_type
"""
result = tx.run(cypher,
username=current_user.username,
project_id=str(project_id),
topic_id=str(topic_id),
viewpoint_id=str(viewpoint_id))
first = result.single()
if first is None:
raise HTTPException(status_code=404, detail="Item not found.")
snapshot_type = first.get("snapshot_type")
return snapshot_type
with self.driver.session() as session:
return session.execute_read(get_viewpoint_snapshot_work)
def get_viewpoint_colored_components(self, project_id: UUID, topic_id: UUID, viewpoint_id: UUID,
current_user: User) -> ColoringGET:
def get_viewpoint_colored_components_work(tx) -> ColoringGET:
cypher = """
MATCH (u:User)-[r1:HAS_ACTIONS_ON]->(p:Project)-[r2:HAS]->(t:Topic)-[r3:HAS]->(v:Viewpoint)-[r4:HAS]->(c:Component)
WHERE u.username = $username
AND r1.read = True
AND p.project_id = $project_id
AND t.guid = $topic_id
AND v.guid = $viewpoint_id
AND c.color IS NOT NULL
RETURN c AS component ORDER BY c.color
"""
results = tx.run(cypher,
username=current_user.username,
project_id=str(project_id),
topic_id=str(topic_id),
viewpoint_id=str(viewpoint_id))
coloring_list = list()
color = ''
coloring = {}
occasion = 0
for result in results:
component_json = self.node_to_json(result.get("component"))
if component_json['color'] != color:
if occasion > 0:
coloring_list.append(coloring)
occasion += 1
color = component_json['color']
coloring = {
'color': color,
'components': []
}
coloring['components'].append(component_json)
coloring_list.append(coloring)
coloring_get = {'coloring': coloring_list}
return ColoringGET(**coloring_get)
with self.driver.session() as session:
return session.execute_read(get_viewpoint_colored_components_work)
def get_viewpoint_selected_components(self, project_id: UUID, topic_id: UUID, viewpoint_id: UUID,
current_user: User) -> SelectionGET:
def get_viewpoint_selected_components_work(tx) -> SelectionGET:
cypher = """
MATCH (u:User)-[r1:HAS_ACTIONS_ON]->(p:Project)-[r2:HAS]->(t:Topic)-[r3:HAS]->(v:Viewpoint)-[r4:HAS]->(c:Component)
WHERE u.username = $username
AND r1.read = True
AND p.project_id = $project_id
AND t.guid = $topic_id
AND v.guid = $viewpoint_id
AND c.selected IS NOT NULL
RETURN c AS component
"""
results = tx.run(cypher,
username=current_user.username,
project_id=str(project_id),
topic_id=str(topic_id),
viewpoint_id=str(viewpoint_id))
component_list = list()
for result in results:
component_json = self.node_to_json(result.get("component"))
component_list.append(component_json)
selection_get = {'selection': component_list}
return SelectionGET(**selection_get)
with self.driver.session() as session:
return session.execute_read(get_viewpoint_selected_components_work)
def get_viewpoint_components_visibility(self, project_id: UUID, topic_id: UUID, viewpoint_id: UUID,
current_user: User) -> VisibilityGET:
def get_viewpoint_components_visibility_work(tx) -> VisibilityGET:
cypher = """
MATCH (u:User)-[r1:HAS_ACTIONS_ON]->(p:Project)-[r2:HAS]->(t:Topic)-[r3:HAS]->(v:Viewpoint)
WHERE u.username = $username
AND r1.read = True
AND p.project_id = $project_id
AND t.guid = $topic_id
AND v.guid = $viewpoint_id
RETURN v AS viewpoint
"""
result = tx.run(cypher,
username=current_user.username,
project_id=str(project_id),
topic_id=str(topic_id),
viewpoint_id=str(viewpoint_id))
first = result.single()
if first is None:
raise HTTPException(status_code=404, detail="Item not found.")
viewpoint_json = self.node_to_json(first.get("viewpoint"))
view_setup_hints = {
'spaces_visible': viewpoint_json['spaces_visible'],
'space_boundaries_visible': viewpoint_json['space_boundaries_visible'],
'openings_visible': viewpoint_json['openings_visible']
}
visibility = {
'default_visibility': viewpoint_json['default_visibility'],
'view_setup_hints': view_setup_hints
}
cypher = """
MATCH (u:User)-[r1:HAS_ACTIONS_ON]->(p:Project)-[r2:HAS]->(t:Topic)-[r3:HAS]->(v:Viewpoint)-[r4:HAS]->(c:Component)
WHERE u.username = $username
AND r1.read = True
AND p.project_id = $project_id
AND t.guid = $topic_id
AND v.guid = $viewpoint_id
AND c.visibility_exception IS NOT NULL
RETURN c AS component
"""
results = tx.run(cypher,
username=current_user.username,
project_id=str(project_id),
topic_id=str(topic_id),
viewpoint_id=str(viewpoint_id))
component_list = list()
for result in results:
component_json = self.node_to_json(result.get("component"))
component_list.append(component_json)
visibility['exceptions'] = component_list
visibility_get = {'visibility': visibility}
return VisibilityGET(**visibility_get)
with self.driver.session() as session:
return session.execute_read(get_viewpoint_components_visibility_work)
# implemented
def delete_viewpoint(self, project_id: UUID, topic_id: UUID, viewpoint_id: UUID, current_user: User) -> int:
def delete_viewpoint_work(tx) -> int:
cypher = """
MATCH (u:User)-[r1:HAS_ACTIONS_ON]->(p:Project)-[r2:HAS]->(t:Topic)-[r3:HAS]->(v:Viewpoint)-[r4:HAS*]->(n)
WHERE u.username = $username
AND r1.update = True
AND p.project_id = $project_id
AND t.guid = $topic_id
AND v.guid = $viewpoint_id
DETACH DELETE v, n
"""
result = tx.run(cypher,
username=current_user.username,
project_id=str(project_id),
topic_id=str(topic_id),
viewpoint_id=str(viewpoint_id))
result_summary = result.consume()
if result_summary.counters.nodes_deleted < 1:
raise HTTPException(status_code=404, detail="Item not found.")
return result_summary.counters.nodes_deleted
with self.driver.session() as session:
self.set_topic_modified_date(project_id, topic_id, current_user)
return session.execute_write(delete_viewpoint_work)
# implemented
# returns a collection
def get_related_topics(self, project_id: UUID, topic_id: UUID, current_user: User) -> List[TopicGET]:
def get_related_topics_work(tx) -> List[TopicGET]:
cypher = """
MATCH (u:User)-[r1:HAS_ACTIONS_ON]->(p:Project)-[r2:HAS]->(t1:Topic)-[r3:RELATED_TO]->(t2:Topic)
WHERE u.username = $username
AND r1.read = True
AND p.project_id = $project_id
AND t1.guid = $topic_id
RETURN t2 AS topic, ID(t2) AS server_assigned_id
"""
results = tx.run(cypher,
username=current_user.username,
project_id=str(project_id),
topic_id=str(topic_id))
topic_model_list = list()
for result in results:
topic_json = self.node_to_json(result.get("topic"))
topic_json["server_assigned_id"] = result.get("server_assigned_id")
topic_model = TopicGET(**topic_json)
topic_model_list.append(topic_model)
return topic_model_list
with self.driver.session() as session:
return session.execute_read(get_related_topics_work)
def put_related_topics(self, project_id: UUID, topic_id: UUID, related_topics: List[RelatedTopicPUT],
current_user: User) -> List[TopicGET]:
def put_related_topics_work(tx) -> bool:
for related_topic in related_topics:
cypher = """
MATCH (u:User)-[r1:HAS_ACTIONS_ON]->(p:Project)-[r2:HAS]->(t1:Topic)
MATCH (p)-[r2:HAS]->(t2:Topic)
WHERE u.username = $username
AND r1.updateRelatedTopics = True
AND p.project_id = $project_id
AND t1.guid = $topic_id
AND t2.guid = $related_topic_id
MERGE (t1)-[r3:RELATED_TO]->(t2:Topic)
"""
tx.run(cypher,
username=current_user.username,
project_id=str(project_id),
topic_id=topic_id,
related_topic_id=related_topic.related_topic_guid)
return True
with self.driver.session() as session:
session.execute_write(put_related_topics_work)
self.set_topic_modified_date(project_id, topic_id, current_user)
return self.get_related_topics(project_id, topic_id, current_user)
# returns a collection
def get_topic_document_references(self, project_id: UUID, topic_id: UUID,
current_user: User) -> List[DocumentReferenceGET]:
def get_topic_document_references_work(tx) -> List[DocumentReferenceGET]:
cypher = """
MATCH (u:User)-[r1:HAS_ACTIONS_ON]->(p:Project)-[r2:HAS]->(t:Topic)-[r3:REFERS_TO]->(d:Document)
WHERE u.username = $username
AND r1.read = True
AND p.project_id = $project_id
AND t.guid = $topic_id
RETURN
r3.guid AS reference_guid,
d.guid AS document_guid,
d.url AS document_url,
d.description AS document_description
"""
results = tx.run(cypher,
username=current_user.username,
project_id=str(project_id),
topic_id=str(topic_id))
document_reference_model_list = list()
for result in results:
document_reference_model = DocumentReferenceGET(**result)
document_reference_model_list.append(document_reference_model)
return document_reference_model_list
with self.driver.session() as session:
return session.execute_read(get_topic_document_references_work)
def post_topic_document_reference(self, project_id: UUID, topic_id: UUID, document_reference: DocumentReferencePOST,
current_user: User) -> List[DocumentReferenceGET]:
def post_topic_document_reference_work(tx) -> bool:
if document_reference.guid is None:
document_reference.guid = uuid4()
if document_reference.document_guid is None or len(document_reference.url) > 4 > len(
document_reference.document_guid):
document_reference.document_guid = uuid4()
document_url = 'd.url = $url,'
else:
document_url = ''
document_reference.url = ''
cypher = """
MATCH (u:User)-[r1:HAS_ACTIONS_ON]->(p:Project)-[r2:HAS]->(t:Topic)
WHERE u.username = $username
AND r1.updateDocumentReferences = True
AND p.project_id = $project_id
AND t.guid = $topic_id
MERGE (t)-[r3:REFERS_TO]->(d:Document {guid: $document_id})
SET r3.guid: $document_reference_id,
%s
d.description = $description
""" % document_url
result = tx.run(cypher,
username=current_user.username,
project_id=str(project_id),
topic_id=str(topic_id),
document_id=str(document_reference.document_guid),
document_reference_id=str(document_reference.guid),
url=document_reference.url,
description=document_reference.description)
summary = result.consume()
if summary.counters.nodes_created < 1:
raise HTTPException(status_code=400, detail="Item not added.")
return True
with self.driver.session() as session:
session.execute_write(post_topic_document_reference_work)
self.set_topic_modified_date(project_id, topic_id, current_user)
return self.get_topic_document_references(project_id, topic_id, current_user)
def put_topic_document_references(self, project_id: UUID, topic_id: UUID, reference_id: UUID,
document_reference: DocumentReferencePUT,
current_user: User) -> List[DocumentReferenceGET]:
document_reference.guid = reference_id
document_reference_post = DocumentReferencePOST(document_reference)
topic_document_references_response = self.post_topic_document_reference(project_id, topic_id,
document_reference_post, current_user)
self.set_topic_modified_date(project_id, topic_id, current_user)
return topic_document_references_response
# returns a collection
def get_documents(self, project_id: UUID, current_user: User):
return True
def post_document(self, project_id: UUID, file: UploadFile, current_user: User):
return True
def get_document(self, project_id: UUID, document_id: UUID, current_user: User):
return True
# returns a collection
def get_topics_events(self, project_id: UUID, topic_id: UUID, current_user: User):
return True
# returns a collection
def get_topic_events(self, project_id: UUID, topic_id: UUID, current_user: User):
return True
# returns a collection
def get_comments_events(self, project_id: UUID, UUID, current_user: User):
return True
# returns a collection
def get_comment_events(self, project_id: UUID, topic_id: UUID, comment_id: UUID, current_user: User):
return True
bcf_db = BCFDB(driver)