diff --git a/src/bcf/bcf/bcfxml.py b/src/bcf/bcf/bcfxml.py index d54e7a1482..9aeb726c51 100644 --- a/src/bcf/bcf/bcfxml.py +++ b/src/bcf/bcf/bcfxml.py @@ -18,6 +18,7 @@ GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with BCF. If not, see . """ + import zipfile from pathlib import Path from typing import Optional, Union diff --git a/src/bcf/bcf/inmemory_zipfile.py b/src/bcf/bcf/inmemory_zipfile.py index c78e9f9a74..2a4d4117ce 100644 --- a/src/bcf/bcf/inmemory_zipfile.py +++ b/src/bcf/bcf/inmemory_zipfile.py @@ -5,6 +5,7 @@ Copyright (c) 2017-2020 Anthon van der Neut, Ruamel bvba original idea from https://stackoverflow.com/a/19722365/1307905 """ + import zipfile from io import BytesIO from os import PathLike @@ -13,8 +14,7 @@ from typing import Any, Optional, Protocol class ZipFileInterface(Protocol): - def writestr(self, filename_in_zip: str | zipfile.ZipInfo, file_contents: bytes | str) -> None: - ... + def writestr(self, filename_in_zip: str | zipfile.ZipInfo, file_contents: bytes | str) -> None: ... class InMemoryZipFile: diff --git a/src/bcf/bcf/v2/bcfxml.py b/src/bcf/bcf/v2/bcfxml.py index de71f65937..fe1d482d61 100644 --- a/src/bcf/bcf/v2/bcfxml.py +++ b/src/bcf/bcf/v2/bcfxml.py @@ -1,4 +1,5 @@ """BCF XML V2 handler.""" + import uuid import warnings import zipfile diff --git a/src/bcf/bcf/v2/model/markup.py b/src/bcf/bcf/v2/model/markup.py index 88ddd3e3a4..0b8fd987aa 100644 --- a/src/bcf/bcf/v2/model/markup.py +++ b/src/bcf/bcf/v2/model/markup.py @@ -34,7 +34,7 @@ class BimSnippet: metadata={ "name": "isExternal", "type": "Attribute", - } + }, ) @@ -64,7 +64,7 @@ class HeaderFile: "name": "Filename", "type": "Element", "namespace": "", - } + }, ) date: Optional[XmlDateTime] = field( default=None, @@ -72,7 +72,7 @@ class HeaderFile: "name": "Date", "type": "Element", "namespace": "", - } + }, ) reference: Optional[str] = field( default=None, @@ -80,7 +80,7 @@ class HeaderFile: "name": "Reference", "type": "Element", "namespace": "", - } + }, ) ifc_project: Optional[str] = field( default=None, @@ -89,7 +89,7 @@ class HeaderFile: "type": "Attribute", "length": 22, "pattern": r"[0-9,A-Z,a-z,_$]*", - } + }, ) ifc_spatial_structure_element: Optional[str] = field( default=None, @@ -98,14 +98,14 @@ class HeaderFile: "type": "Attribute", "length": 22, "pattern": r"[0-9,A-Z,a-z,_$]*", - } + }, ) is_external: bool = field( default=True, metadata={ "name": "isExternal", "type": "Attribute", - } + }, ) @@ -120,7 +120,7 @@ class TopicDocumentReference: "name": "ReferencedDocument", "type": "Element", "namespace": "", - } + }, ) description: Optional[str] = field( default=None, @@ -128,7 +128,7 @@ class TopicDocumentReference: "name": "Description", "type": "Element", "namespace": "", - } + }, ) guid: Optional[str] = field( default=None, @@ -136,14 +136,14 @@ class TopicDocumentReference: "name": "Guid", "type": "Attribute", "pattern": r"[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}", - } + }, ) is_external: bool = field( default=False, metadata={ "name": "isExternal", "type": "Attribute", - } + }, ) @@ -170,7 +170,7 @@ class ViewPoint: "name": "Viewpoint", "type": "Element", "namespace": "", - } + }, ) snapshot: Optional[str] = field( default=None, @@ -178,7 +178,7 @@ class ViewPoint: "name": "Snapshot", "type": "Element", "namespace": "", - } + }, ) index: Optional[int] = field( default=None, @@ -186,7 +186,7 @@ class ViewPoint: "name": "Index", "type": "Element", "namespace": "", - } + }, ) guid: str = field( metadata={ @@ -230,7 +230,7 @@ class Comment: "name": "Viewpoint", "type": "Element", "namespace": "", - } + }, ) modified_date: Optional[XmlDateTime] = field( default=None, @@ -238,7 +238,7 @@ class Comment: "name": "ModifiedDate", "type": "Element", "namespace": "", - } + }, ) modified_author: Optional[str] = field( default=None, @@ -246,7 +246,7 @@ class Comment: "name": "ModifiedAuthor", "type": "Element", "namespace": "", - } + }, ) guid: str = field( metadata={ @@ -267,7 +267,7 @@ class Header: "type": "Element", "namespace": "", "min_occurs": 1, - } + }, ) @@ -279,7 +279,7 @@ class Topic: "name": "ReferenceLink", "type": "Element", "namespace": "", - } + }, ) title: str = field( metadata={ @@ -295,7 +295,7 @@ class Topic: "name": "Priority", "type": "Element", "namespace": "", - } + }, ) index: Optional[int] = field( default=None, @@ -303,7 +303,7 @@ class Topic: "name": "Index", "type": "Element", "namespace": "", - } + }, ) labels: List[str] = field( default_factory=list, @@ -311,7 +311,7 @@ class Topic: "name": "Labels", "type": "Element", "namespace": "", - } + }, ) creation_date: XmlDateTime = field( metadata={ @@ -335,7 +335,7 @@ class Topic: "name": "ModifiedDate", "type": "Element", "namespace": "", - } + }, ) modified_author: Optional[str] = field( default=None, @@ -343,7 +343,7 @@ class Topic: "name": "ModifiedAuthor", "type": "Element", "namespace": "", - } + }, ) due_date: Optional[XmlDateTime] = field( default=None, @@ -351,7 +351,7 @@ class Topic: "name": "DueDate", "type": "Element", "namespace": "", - } + }, ) assigned_to: Optional[str] = field( default=None, @@ -359,7 +359,7 @@ class Topic: "name": "AssignedTo", "type": "Element", "namespace": "", - } + }, ) stage: Optional[str] = field( default=None, @@ -367,7 +367,7 @@ class Topic: "name": "Stage", "type": "Element", "namespace": "", - } + }, ) description: Optional[str] = field( default=None, @@ -375,7 +375,7 @@ class Topic: "name": "Description", "type": "Element", "namespace": "", - } + }, ) bim_snippet: Optional[BimSnippet] = field( default=None, @@ -383,7 +383,7 @@ class Topic: "name": "BimSnippet", "type": "Element", "namespace": "", - } + }, ) document_reference: List[TopicDocumentReference] = field( default_factory=list, @@ -391,7 +391,7 @@ class Topic: "name": "DocumentReference", "type": "Element", "namespace": "", - } + }, ) related_topic: List[TopicRelatedTopic] = field( default_factory=list, @@ -399,7 +399,7 @@ class Topic: "name": "RelatedTopic", "type": "Element", "namespace": "", - } + }, ) guid: str = field( metadata={ @@ -414,14 +414,14 @@ class Topic: metadata={ "name": "TopicType", "type": "Attribute", - } + }, ) topic_status: Optional[str] = field( default=None, metadata={ "name": "TopicStatus", "type": "Attribute", - } + }, ) @@ -433,7 +433,7 @@ class Markup: "name": "Header", "type": "Element", "namespace": "", - } + }, ) topic: Topic = field( metadata={ @@ -449,7 +449,7 @@ class Markup: "name": "Comment", "type": "Element", "namespace": "", - } + }, ) viewpoints: List[ViewPoint] = field( default_factory=list, @@ -457,5 +457,5 @@ class Markup: "name": "Viewpoints", "type": "Element", "namespace": "", - } + }, ) diff --git a/src/bcf/bcf/v2/model/project.py b/src/bcf/bcf/v2/model/project.py index fea44c6f50..e86fb9b009 100644 --- a/src/bcf/bcf/v2/model/project.py +++ b/src/bcf/bcf/v2/model/project.py @@ -10,7 +10,7 @@ class Project: "name": "Name", "type": "Element", "namespace": "", - } + }, ) project_id: str = field( metadata={ @@ -29,7 +29,7 @@ class ProjectExtension: "name": "Project", "type": "Element", "namespace": "", - } + }, ) extension_schema: str = field( metadata={ diff --git a/src/bcf/bcf/v2/model/version.py b/src/bcf/bcf/v2/model/version.py index 777572c6ae..9f55ad5bf9 100644 --- a/src/bcf/bcf/v2/model/version.py +++ b/src/bcf/bcf/v2/model/version.py @@ -10,12 +10,12 @@ class Version: "name": "DetailedVersion", "type": "Element", "namespace": "", - } + }, ) version_id: Optional[str] = field( default=None, metadata={ "name": "VersionId", "type": "Attribute", - } + }, ) diff --git a/src/bcf/bcf/v2/model/visinfo.py b/src/bcf/bcf/v2/model/visinfo.py index f9976e1c78..e1f13d3a37 100644 --- a/src/bcf/bcf/v2/model/visinfo.py +++ b/src/bcf/bcf/v2/model/visinfo.py @@ -15,14 +15,14 @@ class Component: metadata={ "name": "OriginatingSystem", "type": "Element", - } + }, ) authoring_tool_id: Optional[str] = field( default=None, metadata={ "name": "AuthoringToolId", "type": "Element", - } + }, ) ifc_guid: Optional[str] = field( default=None, @@ -31,7 +31,7 @@ class Component: "type": "Attribute", "length": 22, "pattern": r"[0-9,A-Z,a-z,_$]*", - } + }, ) @@ -92,21 +92,21 @@ class ViewSetupHints: metadata={ "name": "SpacesVisible", "type": "Attribute", - } + }, ) space_boundaries_visible: Optional[bool] = field( default=None, metadata={ "name": "SpaceBoundariesVisible", "type": "Attribute", - } + }, ) openings_visible: Optional[bool] = field( default=None, metadata={ "name": "OpeningsVisible", "type": "Attribute", - } + }, ) @@ -139,7 +139,7 @@ class ComponentColoringColor: "name": "Component", "type": "Element", "min_occurs": 1, - } + }, ) color: Optional[str] = field( default=None, @@ -147,7 +147,7 @@ class ComponentColoringColor: "name": "Color", "type": "Attribute", "pattern": r"[0-9,a-f,A-F]{6}([0-9,a-f,A-F]{2})?", - } + }, ) @@ -159,7 +159,7 @@ class ComponentSelection: "name": "Component", "type": "Element", "min_occurs": 1, - } + }, ) @@ -174,7 +174,7 @@ class ComponentVisibilityExceptions: "name": "Component", "type": "Element", "min_occurs": 1, - } + }, ) @@ -205,6 +205,7 @@ class OrthogonalCamera: camera_up_vector: view_to_world_scale: view's visible size in meters """ + camera_view_point: Point = field( metadata={ "name": "CameraViewPoint", @@ -247,6 +248,7 @@ class PerspectiveCamera: release and viewers should be expect values outside this range in current implementations. """ + camera_view_point: Point = field( metadata={ "name": "CameraViewPoint", @@ -336,7 +338,7 @@ class ComponentColoring: "name": "Color", "type": "Element", "min_occurs": 1, - } + }, ) @@ -347,14 +349,14 @@ class ComponentVisibility: metadata={ "name": "Exceptions", "type": "Element", - } + }, ) default_visibility: Optional[bool] = field( default=None, metadata={ "name": "DefaultVisibility", "type": "Attribute", - } + }, ) @@ -368,7 +370,7 @@ class VisualizationInfoClippingPlanes: metadata={ "name": "ClippingPlane", "type": "Element", - } + }, ) @@ -383,7 +385,7 @@ class VisualizationInfoLines: "name": "Line", "type": "Element", "min_occurs": 1, - } + }, ) @@ -394,14 +396,14 @@ class Components: metadata={ "name": "ViewSetupHints", "type": "Element", - } + }, ) selection: Optional[ComponentSelection] = field( default=None, metadata={ "name": "Selection", "type": "Element", - } + }, ) visibility: ComponentVisibility = field( metadata={ @@ -415,7 +417,7 @@ class Components: metadata={ "name": "Coloring", "type": "Element", - } + }, ) @@ -424,47 +426,48 @@ class VisualizationInfo: """ VisualizationInfo documentation. """ + components: Optional[Components] = field( default=None, metadata={ "name": "Components", "type": "Element", - } + }, ) orthogonal_camera: Optional[OrthogonalCamera] = field( default=None, metadata={ "name": "OrthogonalCamera", "type": "Element", - } + }, ) perspective_camera: Optional[PerspectiveCamera] = field( default=None, metadata={ "name": "PerspectiveCamera", "type": "Element", - } + }, ) lines: Optional[VisualizationInfoLines] = field( default=None, metadata={ "name": "Lines", "type": "Element", - } + }, ) clipping_planes: Optional[VisualizationInfoClippingPlanes] = field( default=None, metadata={ "name": "ClippingPlanes", "type": "Element", - } + }, ) bitmap: List[VisualizationInfoBitmap] = field( default_factory=list, metadata={ "name": "Bitmap", "type": "Element", - } + }, ) guid: str = field( metadata={ diff --git a/src/bcf/bcf/v2/topic.py b/src/bcf/bcf/v2/topic.py index c1188c9a06..c23e240700 100644 --- a/src/bcf/bcf/v2/topic.py +++ b/src/bcf/bcf/v2/topic.py @@ -1,4 +1,5 @@ """BCF XML V2 Topic handler.""" + import datetime import tempfile import uuid diff --git a/src/bcf/bcf/v3/bcfxml.py b/src/bcf/bcf/v3/bcfxml.py index 481a7557fa..3318264670 100644 --- a/src/bcf/bcf/v3/bcfxml.py +++ b/src/bcf/bcf/v3/bcfxml.py @@ -1,4 +1,5 @@ """BCF XML V3 handlers.""" + import uuid import warnings import zipfile diff --git a/src/bcf/bcf/v3/document.py b/src/bcf/bcf/v3/document.py index 56a15da42d..afc6be50b9 100644 --- a/src/bcf/bcf/v3/document.py +++ b/src/bcf/bcf/v3/document.py @@ -1,4 +1,5 @@ """BCF XML V3 Documents handler.""" + import zipfile from typing import Any, Optional diff --git a/src/bcf/bcf/v3/model/documents.py b/src/bcf/bcf/v3/model/documents.py index c9a1b43c9c..1b18758d0e 100644 --- a/src/bcf/bcf/v3/model/documents.py +++ b/src/bcf/bcf/v3/model/documents.py @@ -22,7 +22,7 @@ class Document: "namespace": "", "min_length": 1, "white_space": "collapse", - } + }, ) guid: str = field( metadata={ @@ -45,7 +45,7 @@ class DocumentInfoDocuments: "name": "Document", "type": "Element", "namespace": "", - } + }, ) @@ -57,5 +57,5 @@ class DocumentInfo: "name": "Documents", "type": "Element", "namespace": "", - } + }, ) diff --git a/src/bcf/bcf/v3/model/extensions.py b/src/bcf/bcf/v3/model/extensions.py index cb0af500f6..c9c47495ce 100644 --- a/src/bcf/bcf/v3/model/extensions.py +++ b/src/bcf/bcf/v3/model/extensions.py @@ -15,7 +15,7 @@ class ExtensionsPriorities: "namespace": "", "min_length": 1, "white_space": "collapse", - } + }, ) @@ -32,7 +32,7 @@ class ExtensionsSnippetTypes: "namespace": "", "min_length": 1, "white_space": "collapse", - } + }, ) @@ -49,7 +49,7 @@ class ExtensionsStages: "namespace": "", "min_length": 1, "white_space": "collapse", - } + }, ) @@ -66,7 +66,7 @@ class ExtensionsTopicLabels: "namespace": "", "min_length": 1, "white_space": "collapse", - } + }, ) @@ -83,7 +83,7 @@ class ExtensionsTopicStatuses: "namespace": "", "min_length": 1, "white_space": "collapse", - } + }, ) @@ -100,7 +100,7 @@ class ExtensionsTopicTypes: "namespace": "", "min_length": 1, "white_space": "collapse", - } + }, ) @@ -117,7 +117,7 @@ class ExtensionsUsers: "namespace": "", "min_length": 1, "white_space": "collapse", - } + }, ) @@ -129,7 +129,7 @@ class Extensions: "name": "TopicTypes", "type": "Element", "namespace": "", - } + }, ) topic_statuses: Optional[ExtensionsTopicStatuses] = field( default=None, @@ -137,7 +137,7 @@ class Extensions: "name": "TopicStatuses", "type": "Element", "namespace": "", - } + }, ) priorities: Optional[ExtensionsPriorities] = field( default=None, @@ -145,7 +145,7 @@ class Extensions: "name": "Priorities", "type": "Element", "namespace": "", - } + }, ) topic_labels: Optional[ExtensionsTopicLabels] = field( default=None, @@ -153,7 +153,7 @@ class Extensions: "name": "TopicLabels", "type": "Element", "namespace": "", - } + }, ) users: Optional[ExtensionsUsers] = field( default=None, @@ -161,7 +161,7 @@ class Extensions: "name": "Users", "type": "Element", "namespace": "", - } + }, ) snippet_types: Optional[ExtensionsSnippetTypes] = field( default=None, @@ -169,7 +169,7 @@ class Extensions: "name": "SnippetTypes", "type": "Element", "namespace": "", - } + }, ) stages: Optional[ExtensionsStages] = field( default=None, @@ -177,5 +177,5 @@ class Extensions: "name": "Stages", "type": "Element", "namespace": "", - } + }, ) diff --git a/src/bcf/bcf/v3/model/markup.py b/src/bcf/bcf/v3/model/markup.py index f212b9fc7e..4121b04abe 100644 --- a/src/bcf/bcf/v3/model/markup.py +++ b/src/bcf/bcf/v3/model/markup.py @@ -40,7 +40,7 @@ class BimSnippet: metadata={ "name": "IsExternal", "type": "Attribute", - } + }, ) @@ -68,7 +68,7 @@ class DocumentReference: "type": "Element", "namespace": "", "pattern": r"[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}", - } + }, ) url: Optional[str] = field( default=None, @@ -78,7 +78,7 @@ class DocumentReference: "namespace": "", "min_length": 1, "white_space": "collapse", - } + }, ) description: Optional[str] = field( default=None, @@ -88,7 +88,7 @@ class DocumentReference: "namespace": "", "min_length": 1, "white_space": "collapse", - } + }, ) guid: str = field( metadata={ @@ -110,7 +110,7 @@ class File: "namespace": "", "min_length": 1, "white_space": "collapse", - } + }, ) date: Optional[XmlDateTime] = field( default=None, @@ -118,7 +118,7 @@ class File: "name": "Date", "type": "Element", "namespace": "", - } + }, ) reference: Optional[str] = field( default=None, @@ -128,7 +128,7 @@ class File: "namespace": "", "min_length": 1, "white_space": "collapse", - } + }, ) ifc_project: Optional[str] = field( default=None, @@ -137,7 +137,7 @@ class File: "type": "Attribute", "length": 22, "pattern": r"[0-9A-Za-z_$]*", - } + }, ) ifc_spatial_structure_element: Optional[str] = field( default=None, @@ -146,14 +146,14 @@ class File: "type": "Attribute", "length": 22, "pattern": r"[0-9A-Za-z_$]*", - } + }, ) is_external: bool = field( default=True, metadata={ "name": "IsExternal", "type": "Attribute", - } + }, ) @@ -170,7 +170,7 @@ class TopicLabels: "namespace": "", "min_length": 1, "white_space": "collapse", - } + }, ) @@ -187,7 +187,7 @@ class TopicReferenceLinks: "namespace": "", "min_length": 1, "white_space": "collapse", - } + }, ) @@ -216,7 +216,7 @@ class ViewPoint: "namespace": "", "min_length": 1, "white_space": "collapse", - } + }, ) snapshot: Optional[str] = field( default=None, @@ -226,7 +226,7 @@ class ViewPoint: "namespace": "", "min_length": 1, "white_space": "collapse", - } + }, ) index: Optional[int] = field( default=None, @@ -234,7 +234,7 @@ class ViewPoint: "name": "Index", "type": "Element", "namespace": "", - } + }, ) guid: str = field( metadata={ @@ -274,7 +274,7 @@ class Comment: "namespace": "", "min_length": 1, "white_space": "collapse", - } + }, ) viewpoint: Optional[CommentViewpoint] = field( default=None, @@ -282,7 +282,7 @@ class Comment: "name": "Viewpoint", "type": "Element", "namespace": "", - } + }, ) modified_date: Optional[XmlDateTime] = field( default=None, @@ -290,7 +290,7 @@ class Comment: "name": "ModifiedDate", "type": "Element", "namespace": "", - } + }, ) modified_author: Optional[str] = field( default=None, @@ -300,7 +300,7 @@ class Comment: "namespace": "", "min_length": 1, "white_space": "collapse", - } + }, ) guid: str = field( metadata={ @@ -323,7 +323,7 @@ class HeaderFiles: "name": "File", "type": "Element", "namespace": "", - } + }, ) @@ -338,7 +338,7 @@ class TopicDocumentReferences: "name": "DocumentReference", "type": "Element", "namespace": "", - } + }, ) @@ -353,7 +353,7 @@ class TopicRelatedTopics: "name": "RelatedTopic", "type": "Element", "namespace": "", - } + }, ) @@ -368,7 +368,7 @@ class TopicViewpoints: "name": "ViewPoint", "type": "Element", "namespace": "", - } + }, ) @@ -380,7 +380,7 @@ class Header: "name": "Files", "type": "Element", "namespace": "", - } + }, ) @@ -395,7 +395,7 @@ class TopicComments: "name": "Comment", "type": "Element", "namespace": "", - } + }, ) @@ -407,7 +407,7 @@ class Topic: "name": "ReferenceLinks", "type": "Element", "namespace": "", - } + }, ) title: str = field( metadata={ @@ -427,7 +427,7 @@ class Topic: "namespace": "", "min_length": 1, "white_space": "collapse", - } + }, ) index: Optional[int] = field( default=None, @@ -435,7 +435,7 @@ class Topic: "name": "Index", "type": "Element", "namespace": "", - } + }, ) labels: Optional[TopicLabels] = field( default=None, @@ -443,7 +443,7 @@ class Topic: "name": "Labels", "type": "Element", "namespace": "", - } + }, ) creation_date: XmlDateTime = field( metadata={ @@ -469,7 +469,7 @@ class Topic: "name": "ModifiedDate", "type": "Element", "namespace": "", - } + }, ) modified_author: Optional[str] = field( default=None, @@ -479,7 +479,7 @@ class Topic: "namespace": "", "min_length": 1, "white_space": "collapse", - } + }, ) due_date: Optional[XmlDateTime] = field( default=None, @@ -487,7 +487,7 @@ class Topic: "name": "DueDate", "type": "Element", "namespace": "", - } + }, ) assigned_to: Optional[str] = field( default=None, @@ -497,7 +497,7 @@ class Topic: "namespace": "", "min_length": 1, "white_space": "collapse", - } + }, ) stage: Optional[str] = field( default=None, @@ -507,7 +507,7 @@ class Topic: "namespace": "", "min_length": 1, "white_space": "collapse", - } + }, ) description: Optional[str] = field( default=None, @@ -517,7 +517,7 @@ class Topic: "namespace": "", "min_length": 1, "white_space": "collapse", - } + }, ) bim_snippet: Optional[BimSnippet] = field( default=None, @@ -525,7 +525,7 @@ class Topic: "name": "BimSnippet", "type": "Element", "namespace": "", - } + }, ) document_references: Optional[TopicDocumentReferences] = field( default=None, @@ -533,7 +533,7 @@ class Topic: "name": "DocumentReferences", "type": "Element", "namespace": "", - } + }, ) related_topics: Optional[TopicRelatedTopics] = field( default=None, @@ -541,7 +541,7 @@ class Topic: "name": "RelatedTopics", "type": "Element", "namespace": "", - } + }, ) comments: Optional[TopicComments] = field( default=None, @@ -549,7 +549,7 @@ class Topic: "name": "Comments", "type": "Element", "namespace": "", - } + }, ) viewpoints: Optional[TopicViewpoints] = field( default=None, @@ -557,7 +557,7 @@ class Topic: "name": "Viewpoints", "type": "Element", "namespace": "", - } + }, ) guid: str = field( metadata={ @@ -574,7 +574,7 @@ class Topic: "type": "Attribute", "min_length": 1, "white_space": "collapse", - } + }, ) topic_type: str = field( metadata={ @@ -604,7 +604,7 @@ class Markup: "name": "Header", "type": "Element", "namespace": "", - } + }, ) topic: Topic = field( metadata={ diff --git a/src/bcf/bcf/v3/model/project.py b/src/bcf/bcf/v3/model/project.py index b6962213d6..76a6922925 100644 --- a/src/bcf/bcf/v3/model/project.py +++ b/src/bcf/bcf/v3/model/project.py @@ -12,7 +12,7 @@ class Project: "namespace": "", "min_length": 1, "white_space": "collapse", - } + }, ) project_id: str = field( metadata={ diff --git a/src/bcf/bcf/v3/model/visinfo.py b/src/bcf/bcf/v3/model/visinfo.py index fa541945ea..1a1dcb72c5 100644 --- a/src/bcf/bcf/v3/model/visinfo.py +++ b/src/bcf/bcf/v3/model/visinfo.py @@ -17,7 +17,7 @@ class Component: "type": "Element", "min_length": 1, "white_space": "collapse", - } + }, ) authoring_tool_id: Optional[str] = field( default=None, @@ -26,7 +26,7 @@ class Component: "type": "Element", "min_length": 1, "white_space": "collapse", - } + }, ) ifc_guid: Optional[str] = field( default=None, @@ -35,7 +35,7 @@ class Component: "type": "Attribute", "length": 22, "pattern": r"[0-9A-Za-z_$]*", - } + }, ) @@ -96,21 +96,21 @@ class ViewSetupHints: metadata={ "name": "SpacesVisible", "type": "Attribute", - } + }, ) space_boundaries_visible: bool = field( default=False, metadata={ "name": "SpaceBoundariesVisible", "type": "Attribute", - } + }, ) openings_visible: bool = field( default=False, metadata={ "name": "OpeningsVisible", "type": "Attribute", - } + }, ) @@ -191,7 +191,7 @@ class ComponentColoringColorComponents: "name": "Component", "type": "Element", "min_occurs": 1, - } + }, ) @@ -202,7 +202,7 @@ class ComponentSelection: metadata={ "name": "Component", "type": "Element", - } + }, ) @@ -216,7 +216,7 @@ class ComponentVisibilityExceptions: metadata={ "name": "Component", "type": "Element", - } + }, ) @@ -249,6 +249,7 @@ class OrthogonalCamera: aspect_ratio: Proportional relationship between the width and the height of the view (w/h). """ + camera_view_point: Point = field( metadata={ "name": "CameraViewPoint", @@ -302,6 +303,7 @@ class PerspectiveCamera: aspect_ratio: Proportional relationship between the width and the height of the view (w/h). """ + camera_view_point: Point = field( metadata={ "name": "CameraViewPoint", @@ -371,21 +373,21 @@ class ComponentVisibility: metadata={ "name": "ViewSetupHints", "type": "Element", - } + }, ) exceptions: Optional[ComponentVisibilityExceptions] = field( default=None, metadata={ "name": "Exceptions", "type": "Element", - } + }, ) default_visibility: bool = field( default=False, metadata={ "name": "DefaultVisibility", "type": "Attribute", - } + }, ) @@ -399,7 +401,7 @@ class VisualizationInfoBitmaps: metadata={ "name": "Bitmap", "type": "Element", - } + }, ) @@ -413,7 +415,7 @@ class VisualizationInfoClippingPlanes: metadata={ "name": "ClippingPlane", "type": "Element", - } + }, ) @@ -427,7 +429,7 @@ class VisualizationInfoLines: metadata={ "name": "Line", "type": "Element", - } + }, ) @@ -438,7 +440,7 @@ class ComponentColoring: metadata={ "name": "Color", "type": "Element", - } + }, ) @@ -449,21 +451,21 @@ class Components: metadata={ "name": "Selection", "type": "Element", - } + }, ) visibility: Optional[ComponentVisibility] = field( default=None, metadata={ "name": "Visibility", "type": "Element", - } + }, ) coloring: Optional[ComponentColoring] = field( default=None, metadata={ "name": "Coloring", "type": "Element", - } + }, ) @@ -472,47 +474,48 @@ class VisualizationInfo: """ VisualizationInfo documentation. """ + components: Optional[Components] = field( default=None, metadata={ "name": "Components", "type": "Element", - } + }, ) orthogonal_camera: Optional[OrthogonalCamera] = field( default=None, metadata={ "name": "OrthogonalCamera", "type": "Element", - } + }, ) perspective_camera: Optional[PerspectiveCamera] = field( default=None, metadata={ "name": "PerspectiveCamera", "type": "Element", - } + }, ) lines: Optional[VisualizationInfoLines] = field( default=None, metadata={ "name": "Lines", "type": "Element", - } + }, ) clipping_planes: Optional[VisualizationInfoClippingPlanes] = field( default=None, metadata={ "name": "ClippingPlanes", "type": "Element", - } + }, ) bitmaps: Optional[VisualizationInfoBitmaps] = field( default=None, metadata={ "name": "Bitmaps", "type": "Element", - } + }, ) guid: str = field( metadata={ diff --git a/src/bcf/bcf/v3/topic.py b/src/bcf/bcf/v3/topic.py index 71550505ca..927d1e0d74 100644 --- a/src/bcf/bcf/v3/topic.py +++ b/src/bcf/bcf/v3/topic.py @@ -1,4 +1,5 @@ """BCF XML V3 Topic handler.""" + import datetime import uuid import zipfile diff --git a/src/bcf/bcf/xml_parser.py b/src/bcf/bcf/xml_parser.py index b3b51367e0..a5dbd3b71c 100644 --- a/src/bcf/bcf/xml_parser.py +++ b/src/bcf/bcf/xml_parser.py @@ -1,4 +1,5 @@ """XML Parser and Serializer factories.""" + from typing import Optional, Protocol, Type, TypeVar from xsdata.formats.dataclass.context import XmlContext diff --git a/src/bcf/tests/v2/test_bcf_xml.py b/src/bcf/tests/v2/test_bcf_xml.py index 26446ee0c3..fed1428e73 100644 --- a/src/bcf/tests/v2/test_bcf_xml.py +++ b/src/bcf/tests/v2/test_bcf_xml.py @@ -1,4 +1,5 @@ """BCF XML tests.""" + import uuid from pathlib import Path from tempfile import TemporaryDirectory diff --git a/src/bcf/tests/v3/test_bcf_xml.py b/src/bcf/tests/v3/test_bcf_xml.py index 133dd66419..50664b98c7 100644 --- a/src/bcf/tests/v3/test_bcf_xml.py +++ b/src/bcf/tests/v3/test_bcf_xml.py @@ -1,4 +1,5 @@ """BCF XML tests.""" + import uuid from pathlib import Path from tempfile import TemporaryDirectory diff --git a/src/bsdd/tests/test_bsdd.py b/src/bsdd/tests/test_bsdd.py index 2cc1fd3935..8f2421c9d5 100644 --- a/src/bsdd/tests/test_bsdd.py +++ b/src/bsdd/tests/test_bsdd.py @@ -3,39 +3,50 @@ from bsdd import Client client = Client() ifc4x3_uri = [l["uri"] for l in client.get_dictionary()["dictionaries"] if "4.3" in l["uri"]][0] -nbs_uri = [l["uri"] for l in client.get_dictionary()["dictionaries"] if 'Uniclass 2015' == l["name"]][0] +nbs_uri = [l["uri"] for l in client.get_dictionary()["dictionaries"] if "Uniclass 2015" == l["name"]][0] def get_ifc_classes(): - return client.get_classes(ifc4x3_uri, use_nested_classes= False, class_type="Class") + return client.get_classes(ifc4x3_uri, use_nested_classes=False, class_type="Class") + def get_nbs_classes(): - return client.get_classes(nbs_uri, use_nested_classes= False, class_type="Class", offset=0, limit=5) + return client.get_classes(nbs_uri, use_nested_classes=False, class_type="Class", offset=0, limit=5) + def test_get_dictionary(): li_names = [l["name"] for l in client.get_dictionary()["dictionaries"]] - assert 'Uniclass 2015' and 'IFC' in li_names + assert "Uniclass 2015" and "IFC" in li_names + def test_get_ifc_classes(): ifc4x3_classes = get_ifc_classes() assert "IfcBoiler" and "IfcLightFixture" in [l["code"] for l in ifc4x3_classes["classes"]] + def test_get_nbs_classes(): nbs_classes = get_nbs_classes() assert "Ac" in [l["code"] for l in nbs_classes["classes"]] + def test_get_class(): uri_light_fixture = [l for l in get_ifc_classes()["classes"] if "IfcLightFixture" == l["code"]][0]["uri"] ifc4x3_light_fixture = client.get_class(uri_light_fixture) - assert 'Maintenance Factor' and 'Light Fixture Mounting Type' in [l["name"] for l in ifc4x3_light_fixture["classProperties"]] - + assert "Maintenance Factor" and "Light Fixture Mounting Type" in [ + l["name"] for l in ifc4x3_light_fixture["classProperties"] + ] + + def test_search_class(): - ss_heat_pump_sys = client.search_class("Ss_60_40_36", [nbs_uri] ) + ss_heat_pump_sys = client.search_class("Ss_60_40_36", [nbs_uri]) li = [l + "source heat pump systems" for l in ["Air ", "Ground ", "Water "]] - assert len(li) < 8 # I think it should be 4 but just validating it isn't overfetching with some space for future change - for l in li: + assert ( + len(li) < 8 + ) # I think it should be 4 but just validating it isn't overfetching with some space for future change + for l in li: assert l in [_["name"] for _ in ss_heat_pump_sys["classes"]] - + + def test_get_properties(): pr = client.get_properties(ifc4x3_uri, offset=0, limit=5) assert len(pr["properties"]) == 5 diff --git a/src/ifc2ca/_deprecated/ca2ifc.py b/src/ifc2ca/_deprecated/ca2ifc.py index 599a94103f..917ad34eb0 100644 --- a/src/ifc2ca/_deprecated/ca2ifc.py +++ b/src/ifc2ca/_deprecated/ca2ifc.py @@ -1,4 +1,3 @@ - # Ifc2CA - IFC Code_Aster utility # Copyright (C) 2020, 2021 Ioannis P. Christovasilis # diff --git a/src/ifc2ca/_deprecated/scriptCodeAsterBonded.py b/src/ifc2ca/_deprecated/scriptCodeAsterBonded.py index 3264ca20b7..58a7267726 100644 --- a/src/ifc2ca/_deprecated/scriptCodeAsterBonded.py +++ b/src/ifc2ca/_deprecated/scriptCodeAsterBonded.py @@ -55,9 +55,7 @@ class COMMANDFILE: conn["relatedElements"] = [] for el in elements: for rel in el["connections"]: - conn = [ - c for c in connections if c["referenceName"] == rel["relatedConnection"] - ][0] + conn = [c for c in connections if c["referenceName"] == rel["relatedConnection"]][0] conn["relatedElements"].append(rel) # End <-- @@ -65,27 +63,17 @@ class COMMANDFILE: profiles = data["db"]["profiles"] edgeGroupNames = tuple( - [ - self.getGroupName(el["referenceName"]) - for el in elements - if el["geometryType"] == "line" - ] + [self.getGroupName(el["referenceName"]) for el in elements if el["geometryType"] == "line"] ) faceGroupNames = tuple( - [ - self.getGroupName(el["referenceName"]) - for el in elements - if el["geometryType"] == "surface" - ] + [self.getGroupName(el["referenceName"]) for el in elements if el["geometryType"] == "surface"] ) rigidLinkGroupNames = [] for conn in connections: rigidLinkGroupNames.extend( [ - self.getGroupName(rel["relatingElement"]) - + "_1DR_" - + self.getGroupName(conn["referenceName"]) + self.getGroupName(rel["relatingElement"]) + "_1DR_" + self.getGroupName(conn["referenceName"]) for rel in conn["relatedElements"] if rel["eccentricity"] ] @@ -192,20 +180,16 @@ model = AFFE_MODELE( else: if "shearModulus" in material["mechProps"]: poissonRatio = ( - material["mechProps"]["youngModulus"] - / 2.0 - / material["mechProps"]["shearModulus"] + material["mechProps"]["youngModulus"] / 2.0 / material["mechProps"]["shearModulus"] ) - 1 else: poissonRatio = 0.0 context = { "matNameID": "mat" + "_%s" % i, - "youngModulus": float(material["mechProps"]["youngModulus"]) - * ScaleFactor ** 2, + "youngModulus": float(material["mechProps"]["youngModulus"]) * ScaleFactor**2, "poissonRatio": float(poissonRatio), - "massDensity": float(material["commonProps"]["massDensity"]) - * ScaleFactor ** 3, + "massDensity": float(material["commonProps"]["massDensity"]) * ScaleFactor**3, } f.write(template.format(**context)) @@ -225,9 +209,7 @@ material = AFFE_MATERIAU( ),""" context = { - "groupNames": tuple( - [self.getGroupName(rel) for rel in material["relatedElements"]] - ), + "groupNames": tuple([self.getGroupName(rel) for rel in material["relatedElements"]]), "matNameID": "mat" + "_%s" % i, } @@ -260,10 +242,7 @@ element = AFFE_CARA_ELEM( ) for profile in profiles: - if ( - profile["profileShape"] == "rectangular" - and profile["profileType"] == "AREA" - ): + if profile["profileShape"] == "rectangular" and profile["profileType"] == "AREA": template = """ _F( GROUP_MA = {groupNames}, @@ -273,9 +252,7 @@ element = AFFE_CARA_ELEM( ),""" context = { - "groupNames": tuple( - [self.getGroupName(rel) for rel in profile["relatedElements"]] - ), + "groupNames": tuple([self.getGroupName(rel) for rel in profile["relatedElements"]]), "profileDimensions": ( profile["xDim"] / ScaleFactor, profile["yDim"] / ScaleFactor, @@ -284,10 +261,7 @@ element = AFFE_CARA_ELEM( f.write(template.format(**context)) - elif ( - profile["profileShape"] == "iSymmetrical" - and profile["profileType"] == "AREA" - ): + elif profile["profileShape"] == "iSymmetrical" and profile["profileType"] == "AREA": template = """ _F( GROUP_MA = {groupNames}, @@ -297,14 +271,12 @@ element = AFFE_CARA_ELEM( ),""" context = { - "groupNames": tuple( - [self.getGroupName(rel) for rel in profile["relatedElements"]] - ), + "groupNames": tuple([self.getGroupName(rel) for rel in profile["relatedElements"]]), "profileProperties": ( - profile["mechProps"]["crossSectionArea"] / ScaleFactor ** 2, - profile["mechProps"]["momentOfInertiaY"] / ScaleFactor ** 4, - profile["mechProps"]["momentOfInertiaZ"] / ScaleFactor ** 4, - profile["mechProps"]["torsionalConstantX"] / ScaleFactor ** 4, + profile["mechProps"]["crossSectionArea"] / ScaleFactor**2, + profile["mechProps"]["momentOfInertiaY"] / ScaleFactor**4, + profile["mechProps"]["momentOfInertiaZ"] / ScaleFactor**4, + profile["mechProps"]["torsionalConstantX"] / ScaleFactor**4, ), } @@ -572,9 +544,7 @@ if __name__ == "__main__": files = fileNames for fileName in files: - BASE_PATH = Path( - "/home/jesusbill/Dev-Projects/github.com/IfcOpenShell/analysis-models/models/" - ) + BASE_PATH = Path("/home/jesusbill/Dev-Projects/github.com/IfcOpenShell/analysis-models/models/") DATAFILENAME = BASE_PATH / fileName / f"{fileName}.json" ASTERFILENAME = BASE_PATH / fileName / f"{fileName}.comm" COMMANDFILE(DATAFILENAME, ASTERFILENAME) diff --git a/src/ifc2ca/_deprecated/scriptSalomeBonded.py b/src/ifc2ca/_deprecated/scriptSalomeBonded.py index 2a68869ec9..4cde543334 100644 --- a/src/ifc2ca/_deprecated/scriptSalomeBonded.py +++ b/src/ifc2ca/_deprecated/scriptSalomeBonded.py @@ -30,6 +30,7 @@ from pathlib import Path flatten = itertools.chain.from_iterable + class MODEL: def __init__(self, dataFilename, medFilename, meshSize, zGround): self.dataFilename = dataFilename @@ -97,9 +98,7 @@ class MODEL: shapeType = "EDGE" if geometryType == "surface": shapeType = "FACE" - return self.geompy.MakePartition( - objects, [], [], [], self.geompy.ShapeType[shapeType], 0, [], 1 - ) + return self.geompy.MakePartition(objects, [], [], [], self.geompy.ShapeType[shapeType], 0, [], 1) def getLinkGeometry(self, ecc, orientation, finalPoint): vector = np.array(orientation).transpose().dot(ecc["vector"]) @@ -195,29 +194,21 @@ class MODEL: el["linkObjs"] = [None for _ in el["connections"]] for j, rel in enumerate(el["connections"]): - conn = [ - c for c in connections if c["referenceName"] == rel["relatedConnection"] - ][0] + conn = [c for c in connections if c["referenceName"] == rel["relatedConnection"]][0] if rel["eccentricity"]: rel["index"] = len(conn["relatedElements"]) + 1 - geometry = self.getLinkGeometry( - rel["eccentricity"], el["orientation"], conn["geometry"] - ) + geometry = self.getLinkGeometry(rel["eccentricity"], el["orientation"], conn["geometry"]) el["linkObjs"][j] = self.makeObject(geometry, "line") conn["relatedElements"].append(rel) # Make assemble of Building Object bldObjs = [] bldObjs.extend([el["elemObj"] for el in elements]) - bldObjs.extend( - flatten([[link for link in el["linkObjs"] if link] for el in elements]) - ) + bldObjs.extend(flatten([[link for link in el["linkObjs"] if link] for el in elements])) # bldComp = geompy.MakeCompound(bldObjs) - bldComp = geompy.MakePartition( - bldObjs, [], [], [], self.geompy.ShapeType[buildingShapeType], 0, [], 1 - ) + bldComp = geompy.MakePartition(bldObjs, [], [], [], self.geompy.ShapeType[buildingShapeType], 0, [], 1) geompy.addToStudy(bldComp, "bldComp") elapsed_time = time.time() - init_time @@ -227,25 +218,19 @@ class MODEL: # Define and add groups for all curve, surface and rigid members if len([e for e in elements if e["geometryType"] == "line"]) > 0: # Make compound of requested group - compoundTemp = geompy.MakeCompound( - [e["elemObj"] for e in elements if e["geometryType"] == "line"] - ) + compoundTemp = geompy.MakeCompound([e["elemObj"] for e in elements if e["geometryType"] == "line"]) # Define group object and add to study curveCompound = geompy.GetInPlace(bldComp, compoundTemp, True) geompy.addToStudyInFather(bldComp, curveCompound, "CurveMembers") if len([e for e in elements if e["geometryType"] == "surface"]) > 0: # Make compound of requested group - compoundTemp = geompy.MakeCompound( - [e["elemObj"] for e in elements if e["geometryType"] == "surface"] - ) + compoundTemp = geompy.MakeCompound([e["elemObj"] for e in elements if e["geometryType"] == "surface"]) # Define group object and add to study surfaceCompound = geompy.GetInPlace(bldComp, compoundTemp, True) geompy.addToStudyInFather(bldComp, surfaceCompound, "SurfaceMembers") - linkObjs = list( - flatten([[obj for obj in el["linkObjs"] if obj] for el in elements]) - ) + linkObjs = list(flatten([[obj for obj in el["linkObjs"] if obj] for el in elements])) if len(linkObjs) > 0: # Make compound of requested group compoundTemp = geompy.MakeCompound(linkObjs) @@ -256,21 +241,15 @@ class MODEL: for el in elements: # el['partObj'] = geompy.RestoreGivenSubShapes(bldComp, [el['partObj']], GEOM.FSM_GetInPlace, False, False)[0] el["elemObj"] = geompy.GetInPlace(bldComp, el["elemObj"], True) - geompy.addToStudyInFather( - bldComp, el["elemObj"], self.getGroupName(el["referenceName"]) - ) + geompy.addToStudyInFather(bldComp, el["elemObj"], self.getGroupName(el["referenceName"])) for j, rel in enumerate(el["connections"]): if rel["eccentricity"]: # point geometry - el["linkObjs"][j] = geompy.GetInPlace( - bldComp, el["linkObjs"][j], True - ) + el["linkObjs"][j] = geompy.GetInPlace(bldComp, el["linkObjs"][j], True) geompy.addToStudyInFather( bldComp, el["linkObjs"][j], - self.getGroupName(el["referenceName"]) - + "_1DR_" - + self.getGroupName(rel["relatedConnection"]), + self.getGroupName(el["referenceName"]) + "_1DR_" + self.getGroupName(rel["relatedConnection"]), ) elapsed_time = time.time() - init_time @@ -307,9 +286,7 @@ class MODEL: NETGEN2D_Pars.SetFuseEdges(254) isDone = bldMesh.Compute() - coincident_nodes_on_part = bldMesh.FindCoincidentNodesOnPart( - [bldMesh], tolLoc, [], 0 - ) + coincident_nodes_on_part = bldMesh.FindCoincidentNodesOnPart([bldMesh], tolLoc, [], 0) if coincident_nodes_on_part: # bldMesh.MergeNodes(coincident_nodes_on_part, [], 0) # print(f'{len(coincident_nodes_on_part)} Sets of Coincident Nodes Found and Merged') @@ -349,25 +326,19 @@ class MODEL: shapeType = SMESH.EDGE if el["geometryType"] == "surface": shapeType = SMESH.FACE - tempgroup = bldMesh.GroupOnGeom( - el["elemObj"], self.getGroupName(el["referenceName"]), shapeType - ) + tempgroup = bldMesh.GroupOnGeom(el["elemObj"], self.getGroupName(el["referenceName"]), shapeType) smesh.SetName(tempgroup, self.getGroupName(el["referenceName"])) for j, rel in enumerate(el["connections"]): if rel["eccentricity"]: tempgroup = bldMesh.GroupOnGeom( el["linkObjs"][j], - self.getGroupName(el["referenceName"]) - + "_1DR_" - + self.getGroupName(rel["relatedConnection"]), + self.getGroupName(el["referenceName"]) + "_1DR_" + self.getGroupName(rel["relatedConnection"]), SMESH.EDGE, ) smesh.SetName( tempgroup, - self.getGroupName(el["referenceName"]) - + "_1DR_" - + self.getGroupName(rel["relatedConnection"]), + self.getGroupName(el["referenceName"]) + "_1DR_" + self.getGroupName(rel["relatedConnection"]), ) self.mesh = bldMesh @@ -420,9 +391,7 @@ if __name__ == "__main__": zGround = 0 for fileName in files: - BASE_PATH = Path( - "/home/jesusbill/Dev-Projects/github.com/IfcOpenShell/analysis-models/models/" - ) + BASE_PATH = Path("/home/jesusbill/Dev-Projects/github.com/IfcOpenShell/analysis-models/models/") DATAFILENAME = BASE_PATH / fileName / f"{fileName}.json" MEDFILENAME = BASE_PATH / fileName / f"{fileName}.med" model = MODEL(DATAFILENAME, str(MEDFILENAME), meshSize, zGround) diff --git a/src/ifc2ca/ca2ifc.py b/src/ifc2ca/ca2ifc.py index 151edce378..f2be1bf0cc 100644 --- a/src/ifc2ca/ca2ifc.py +++ b/src/ifc2ca/ca2ifc.py @@ -1,4 +1,3 @@ - # Ifc2CA - IFC Code_Aster utility # Copyright (C) 2020, 2021, 2023, 2024 Ioannis P. Christovasilis # diff --git a/src/ifc2ca/ifc2ca.py b/src/ifc2ca/ifc2ca.py index 2dd4b04263..b380804dbb 100644 --- a/src/ifc2ca/ifc2ca.py +++ b/src/ifc2ca/ifc2ca.py @@ -24,10 +24,12 @@ from pathlib import Path from typing import Dict, List import ifcopenshell as ios + # import ifcopenshell.geom import ifcopenshell.util.element import ifcopenshell.util.placement import ifcopenshell.util.representation + # import ifcopenshell.util.shape import numpy as np from jinja2 import Environment, FileSystemLoader diff --git a/src/ifc4d/__main__.py b/src/ifc4d/__main__.py index a4e8087a54..d7e2a58307 100644 --- a/src/ifc4d/__main__.py +++ b/src/ifc4d/__main__.py @@ -9,23 +9,26 @@ from ifc4d.pp2ifc import PP2Ifc import ifcopenshell -parser = argparse.ArgumentParser() -parser .add_argument('-f','--file', action='store', type=str, - required=True, help="schedule file name to be parsed") -parser .add_argument('-s','--schedule', action='store', required=True, - type=str, help='file format as xer, p6xml, mspxml, pp') -parser .add_argument('-i', '--ifcfile', action='store', required=False, - type=str, help='ifc file name as string e.g. \"file.ifc\"') -parser .add_argument('-o', '--output', action='store', required=True, - type=str, help='ifc file name as string e.g. \"file.ifc\"') -args = parser .parse_args() +parser = argparse.ArgumentParser() +parser.add_argument("-f", "--file", action="store", type=str, required=True, help="schedule file name to be parsed") +parser.add_argument( + "-s", "--schedule", action="store", required=True, type=str, help="file format as xer, p6xml, mspxml, pp" +) +parser.add_argument( + "-i", "--ifcfile", action="store", required=False, type=str, help='ifc file name as string e.g. "file.ifc"' +) +parser.add_argument( + "-o", "--output", action="store", required=True, type=str, help='ifc file name as string e.g. "file.ifc"' +) +args = parser.parse_args() + def get_file(): ifcfile = None if args.ifcfile: ifcfile = ifcopenshell.open(args.ifcfile) elif args.output: - ifc = ifcopenshell.file(schema='IFC4') + ifc = ifcopenshell.file(schema="IFC4") ifc.create_entity("IfcWorkPlan") ifc.create_entity("IfcProject") ifc.write(args.output) @@ -34,6 +37,7 @@ def get_file(): ifcfile = None return ifcfile + if not args.ifcfile: print("You need to provide an ifc file to add schedule") print("Examples python ifc4d -i model.ifc -s xer -f schedule.xer -o newifc.ifc") @@ -41,7 +45,7 @@ elif not args.output: print("an output file is required to save changes") print("python ifc4d -o newfile.ifc -s xer -f schedule.xer") -elif args.schedule== "xer": +elif args.schedule == "xer": p6xer = P6XER2Ifc() p6xer.xer = args.file p6xer.output = args.output @@ -49,7 +53,8 @@ elif args.schedule== "xer": if ifcfile: p6xer.file = ifcfile p6xer.execute() - else: raise Exception("No files provided for output") + else: + raise Exception("No files provided for output") elif args.schedule == "mspxml": msp = MSP2Ifc() msp.xml = args.file() @@ -76,4 +81,3 @@ elif args.schedule == "pp": pp.execute() else: print("schedule type you selected is not implemented at the moment") - diff --git a/src/ifc4d/ifc4d/common.py b/src/ifc4d/ifc4d/common.py index e12281dd5b..96ffe7a0af 100644 --- a/src/ifc4d/ifc4d/common.py +++ b/src/ifc4d/ifc4d/common.py @@ -246,12 +246,11 @@ class ScheduleIfcGenerator: "ScheduleStart": activity["StartDate"], "ScheduleFinish": activity["FinishDate"], "DurationType": "WORKTIME" if activity["PlannedDuration"] else None, - "ScheduleDuration": timedelta( - days=float(activity["PlannedDuration"]) / float(calendar["HoursPerDay"] or 8) - ) - or None - if activity["PlannedDuration"] - else None, + "ScheduleDuration": ( + timedelta(days=float(activity["PlannedDuration"]) / float(calendar["HoursPerDay"] or 8)) or None + if activity["PlannedDuration"] + else None + ), }, ) diff --git a/src/ifc4d/ifc4d/csv4d2ifc.py b/src/ifc4d/ifc4d/csv4d2ifc.py index 3204311d9d..19554614d2 100644 --- a/src/ifc4d/ifc4d/csv4d2ifc.py +++ b/src/ifc4d/ifc4d/csv4d2ifc.py @@ -86,12 +86,36 @@ class Csv2Ifc: task_relationships = self.parse_task_rel(row[self.headers["Relationships"]]) - scheduled_start_date = ifcopenshell.util.date.string_to_date(row[self.headers["ScheduleStart"]]) if row[self.headers["ScheduleStart"]] else None - scheduled_finish_date = ifcopenshell.util.date.string_to_date(row[self.headers["ScheduleFinish"]]) if row[self.headers["ScheduleFinish"]] else None - scheduled_duration = ifcopenshell.util.date.string_to_duration(row[self.headers["ScheduleDuration"]]) if row[self.headers["ScheduleDuration"]] else None - actual_start_date = ifcopenshell.util.date.string_to_date(row[self.headers["ActualStart"]]) if row[self.headers["ActualStart"]] else None - actual_finish_date = ifcopenshell.util.date.string_to_date(row[self.headers["ActualFinish"]]) if row[self.headers["ActualFinish"]] else None - actual_duration = ifcopenshell.util.date.string_to_duration(row[self.headers["ActualDuration"]]) if row[self.headers["ActualDuration"]] else None + scheduled_start_date = ( + ifcopenshell.util.date.string_to_date(row[self.headers["ScheduleStart"]]) + if row[self.headers["ScheduleStart"]] + else None + ) + scheduled_finish_date = ( + ifcopenshell.util.date.string_to_date(row[self.headers["ScheduleFinish"]]) + if row[self.headers["ScheduleFinish"]] + else None + ) + scheduled_duration = ( + ifcopenshell.util.date.string_to_duration(row[self.headers["ScheduleDuration"]]) + if row[self.headers["ScheduleDuration"]] + else None + ) + actual_start_date = ( + ifcopenshell.util.date.string_to_date(row[self.headers["ActualStart"]]) + if row[self.headers["ActualStart"]] + else None + ) + actual_finish_date = ( + ifcopenshell.util.date.string_to_date(row[self.headers["ActualFinish"]]) + if row[self.headers["ActualFinish"]] + else None + ) + actual_duration = ( + ifcopenshell.util.date.string_to_duration(row[self.headers["ActualDuration"]]) + if row[self.headers["ActualDuration"]] + else None + ) return { "Hierarchy": hierarchy, @@ -191,7 +215,7 @@ class Csv2Ifc: self.file, related_process=task_2, relating_process=task_1, - sequence_type = rel_type, + sequence_type=rel_type, ) if rel_type: ifcopenshell.api.run( diff --git a/src/ifc4d/ifc4d/ifc2p6.py b/src/ifc4d/ifc4d/ifc2p6.py index 7d3b9e4598..f0569d7873 100644 --- a/src/ifc4d/ifc4d/ifc2p6.py +++ b/src/ifc4d/ifc4d/ifc2p6.py @@ -46,9 +46,9 @@ class Ifc2P6: self.root = ET.Element("APIBusinessObjects") self.root.attrib["xmlns"] = "http://xmlns.oracle.com/Primavera/P6Professional/V18.8/API/BusinessObjects" self.root.attrib["xmlns:xsi"] = "http://www.w3.org/2001/XMLSchema-instance" - self.root.attrib[ - "xsi:schemaLocation" - ] = "http://xmlns.oracle.com/Primavera/P6Professional/V18.8/API/BusinessObjects http://xmlns.oracle.com/Primavera/P6Professional/V18.8/API/p6apibo.xsd" + self.root.attrib["xsi:schemaLocation"] = ( + "http://xmlns.oracle.com/Primavera/P6Professional/V18.8/API/BusinessObjects http://xmlns.oracle.com/Primavera/P6Professional/V18.8/API/p6apibo.xsd" + ) self.schedule = self.file.by_type("IfcWorkSchedule")[0] diff --git a/src/ifc4d/ifc4d/msp2ifc.py b/src/ifc4d/ifc4d/msp2ifc.py index face82e7e9..fb0f7acab0 100644 --- a/src/ifc4d/ifc4d/msp2ifc.py +++ b/src/ifc4d/ifc4d/msp2ifc.py @@ -112,13 +112,12 @@ class MSP2Ifc: # If first column = "all" then retrieve all columns if len(self.optionalColumns) and self.optionalColumns[0] == "all": self.optionalColumns = [child.tag.split("}")[1] for child in task] - + for column in self.optionalColumns: if not self.tasks[task_id].get(column): - self.tasks[task_id][column] = task.find(f"pr:{column}", self.ns).text if task.find(f"pr:{column}", self.ns) else None - - - + self.tasks[task_id][column] = ( + task.find(f"pr:{column}", self.ns).text if task.find(f"pr:{column}", self.ns) else None + ) def parse_calendar_xml(self, project): def parse_working_times(day): @@ -139,27 +138,37 @@ class MSP2Ifc: work_times = parse_working_times(exception) time_period = exception.find("pr:TimePeriod", self.ns) data = { - "Name": exception.find("pr:Name", self.ns).text - if exception.find("pr:Name", self.ns) is not None - else None, - "FromDate": datetime.datetime.fromisoformat(time_period.find("pr:FromDate", self.ns).text) - if time_period is not None - else None, - "ToDate": datetime.datetime.fromisoformat(time_period.find("pr:ToDate", self.ns).text) - if time_period is not None - else None, - "Occurrences": int(exception.find("pr:Occurrences", self.ns).text) - if exception.find("pr:Occurrences", self.ns) is not None - else None, - "Month": exception.find("pr:Month", self.ns).text - if exception.find("pr:Month", self.ns) is not None - else None, - "MonthDay": exception.find("pr:MonthDay", self.ns).text - if exception.find("pr:MonthDay", self.ns) is not None - else None, - "Type": exception.find("pr:Type", self.ns).text - if exception.find("pr:Type", self.ns) is not None - else None, + "Name": ( + exception.find("pr:Name", self.ns).text if exception.find("pr:Name", self.ns) is not None else None + ), + "FromDate": ( + datetime.datetime.fromisoformat(time_period.find("pr:FromDate", self.ns).text) + if time_period is not None + else None + ), + "ToDate": ( + datetime.datetime.fromisoformat(time_period.find("pr:ToDate", self.ns).text) + if time_period is not None + else None + ), + "Occurrences": ( + int(exception.find("pr:Occurrences", self.ns).text) + if exception.find("pr:Occurrences", self.ns) is not None + else None + ), + "Month": ( + exception.find("pr:Month", self.ns).text + if exception.find("pr:Month", self.ns) is not None + else None + ), + "MonthDay": ( + exception.find("pr:MonthDay", self.ns).text + if exception.find("pr:MonthDay", self.ns) is not None + else None + ), + "Type": ( + exception.find("pr:Type", self.ns).text if exception.find("pr:Type", self.ns) is not None else None + ), "WorkingTimes": work_times, "ifc": None, } @@ -283,16 +292,15 @@ class MSP2Ifc: for subtask_id in task["subtasks"]: self.create_task(self.tasks[subtask_id], parent_task=task) - # create pset for optional columns if len(self.optionalColumns): - pset = ifcopenshell.api.run("pset.add_pset", self.file, product=task["ifc"] , name="Pset_MSP_Task") + pset = ifcopenshell.api.run("pset.add_pset", self.file, product=task["ifc"], name="Pset_MSP_Task") ifcopenshell.api.run( "pset.edit_pset", self.file, pset=pset, - properties= {name: str(task[name]) for name in self.optionalColumns if task[name]} + properties={name: str(task[name]) for name in self.optionalColumns if task[name]}, ) def process_working_week(self, week, calendar): diff --git a/src/ifc4d/ifc4d/wpattern.py b/src/ifc4d/ifc4d/wpattern.py index e69d8d0872..304f03777a 100644 --- a/src/ifc4d/ifc4d/wpattern.py +++ b/src/ifc4d/ifc4d/wpattern.py @@ -62,6 +62,7 @@ class AstaCalendarWorkPattern: if wp["DayOfWeek"] == days[lang][index]: wp["DayOfWeek"] = days["en"][index] return + translate_days(self.Days, self.dict_wp[-1]) for day in self.Days["en"]: diff --git a/src/ifcbimtester/bimtester/features/steps/geolocation/en.py b/src/ifcbimtester/bimtester/features/steps/geolocation/en.py index 9d7105e64a..596aa858cf 100644 --- a/src/ifcbimtester/bimtester/features/steps/geolocation/en.py +++ b/src/ifcbimtester/bimtester/features/steps/geolocation/en.py @@ -30,7 +30,7 @@ from bimtester.ifc import IfcStore from bimtester.lang import _ -@step(u'There must be at least one "{ifc_class}" element') +@step('There must be at least one "{ifc_class}" element') def step_impl(context, ifc_class): assert len(IfcStore.file.by_type(ifc_class)) >= 1, _("An element of {} could not be found").format(ifc_class) @@ -68,7 +68,7 @@ def check_ifc4_geolocation(entity_name, prop_name=None, value=None, should_asser return actual_value -@step(u"The project must have coordinate reference system data") +@step("The project must have coordinate reference system data") def step_impl(context): if IfcStore.file.schema == "IFC2X3": for site in IfcStore.file.by_type("IfcSite"): @@ -77,7 +77,7 @@ def step_impl(context): check_ifc4_geolocation("IfcProjectedCRS") -@step(u'The name of the CRS must be "{coordinate_reference_name}"') +@step('The name of the CRS must be "{coordinate_reference_name}"') def step_impl(context, coordinate_reference_name): if IfcStore.file.schema == "IFC2X3": for site in IfcStore.file.by_type("IfcSite"): @@ -86,7 +86,7 @@ def step_impl(context, coordinate_reference_name): check_ifc4_geolocation("IfcProjectedCRS", "Name", coordinate_reference_name) -@step(u'The description of the CRS must be "{value}"') +@step('The description of the CRS must be "{value}"') def step_impl(context, value): if IfcStore.file.schema == "IFC2X3": for site in IfcStore.file.by_type("IfcSite"): @@ -95,7 +95,7 @@ def step_impl(context, value): check_ifc4_geolocation("IfcProjectedCRS", "Description", value) -@step(u'The geodetic datum must be "{coordinate_reference_name}"') +@step('The geodetic datum must be "{coordinate_reference_name}"') def step_impl(context, coordinate_reference_name): if IfcStore.file.schema == "IFC2X3": for site in IfcStore.file.by_type("IfcSite"): @@ -104,7 +104,7 @@ def step_impl(context, coordinate_reference_name): check_ifc4_geolocation("IfcProjectedCRS", "GeodeticDatum", coordinate_reference_name) -@step(u'The vertical datum must be "{coordinate_reference_name}"') +@step('The vertical datum must be "{coordinate_reference_name}"') def step_impl(context, coordinate_reference_name): if IfcStore.file.schema == "IFC2X3": for site in IfcStore.file.by_type("IfcSite"): @@ -113,7 +113,7 @@ def step_impl(context, coordinate_reference_name): check_ifc4_geolocation("IfcProjectedCRS", "VerticalDatum", coordinate_reference_name) -@step(u'The map projection must be "{coordinate_reference_name}"') +@step('The map projection must be "{coordinate_reference_name}"') def step_impl(context, coordinate_reference_name): if IfcStore.file.schema == "IFC2X3": for site in IfcStore.file.by_type("IfcSite"): @@ -122,7 +122,7 @@ def step_impl(context, coordinate_reference_name): check_ifc4_geolocation("IfcProjectedCRS", "MapProjection", coordinate_reference_name) -@step(u'The map zone must be "{coordinate_reference_name}"') +@step('The map zone must be "{coordinate_reference_name}"') def step_impl(context, coordinate_reference_name): if IfcStore.file.schema == "IFC2X3": for site in IfcStore.file.by_type("IfcSite"): @@ -131,7 +131,7 @@ def step_impl(context, coordinate_reference_name): check_ifc4_geolocation("IfcProjectedCRS", "MapZone", coordinate_reference_name) -@step(u'The map unit must be "{unit}"') +@step('The map unit must be "{unit}"') def step_impl(context, unit): if IfcStore.file.schema == "IFC2X3": for site in IfcStore.file.by_type("IfcSite"): @@ -148,7 +148,7 @@ def step_impl(context, unit): assert actual_value == unit, _('We expected a value of "{}" but instead got "{}"').format(unit, actual_value) -@step(u"The project must have coordinate transformations to convert from local to global coordinates") +@step("The project must have coordinate transformations to convert from local to global coordinates") def step_impl(context): if IfcStore.file.schema == "IFC2X3": for site in IfcStore.file.by_type("IfcSite"): @@ -156,7 +156,7 @@ def step_impl(context): check_ifc4_geolocation("IfcMapConversion") -@step(u'The eastings of the model must be offset by "{number}" to derive its global coordinates') +@step('The eastings of the model must be offset by "{number}" to derive its global coordinates') def step_impl(context, number): number = util.assert_number(number) if IfcStore.file.schema == "IFC2X3": @@ -166,7 +166,7 @@ def step_impl(context, number): check_ifc4_geolocation("IfcMapConversion", "Eastings", number) -@step(u'The northings of the model must be offset by "{number}" to derive its global coordinates') +@step('The northings of the model must be offset by "{number}" to derive its global coordinates') def step_impl(context, number): number = util.assert_number(number) if IfcStore.file.schema == "IFC2X3": @@ -176,7 +176,7 @@ def step_impl(context, number): check_ifc4_geolocation("IfcMapConversion", "Northings", number) -@step(u'The height of the model must be offset by "{number}" to derive its global coordinates') +@step('The height of the model must be offset by "{number}" to derive its global coordinates') def step_impl(context, number): number = util.assert_number(number) if IfcStore.file.schema == "IFC2X3": @@ -186,7 +186,7 @@ def step_impl(context, number): check_ifc4_geolocation("IfcMapConversion", "OrthogonalHeight", number) -@step(u'The model must be rotated clockwise by "{number}" to derive its global coordinates') +@step('The model must be rotated clockwise by "{number}" to derive its global coordinates') def step_impl(context, number): number = util.assert_number(number) if IfcStore.file.schema == "IFC2X3": @@ -198,7 +198,7 @@ def step_impl(context, number): assert actual_value == value, _('We expected a value of "{}" but instead got "{}"').format(value, actual_value) -@step(u'The model must be scaled along the horizontal axis by "{number}" to derive its global coordinates') +@step('The model must be scaled along the horizontal axis by "{number}" to derive its global coordinates') def step_impl(context, number): number = util.assert_number(number) if IfcStore.file.schema == "IFC2X3": @@ -208,7 +208,7 @@ def step_impl(context, number): check_ifc4_geolocation("IfcMapConversion", "Scale", number) -@step(u'The model must be rotated clockwise by "{number}" for true north to point up') +@step('The model must be rotated clockwise by "{number}" for true north to point up') def step_impl(context, number): number = util.assert_number(number) project = IfcStore.file.by_type("IfcProject")[0] @@ -228,7 +228,7 @@ def step_impl(context, number): assert False, _("True north is not defined in the file") -@step(u'The site "{guid}" has a longitude of "{number}"') +@step('The site "{guid}" has a longitude of "{number}"') def step_impl(context, guid, number): number = util.assert_number(number) site = util.assert_guid(IfcStore.file, guid) @@ -238,7 +238,7 @@ def step_impl(context, guid, number): util.assert_attribute(site, "RefLongitude", number) -@step(u'The site "{guid}" has a latitude of "{number}"') +@step('The site "{guid}" has a latitude of "{number}"') def step_impl(context, guid, number): number = util.assert_number(number) site = util.assert_guid(IfcStore.file, guid) @@ -248,7 +248,7 @@ def step_impl(context, guid, number): util.assert_attribute(site, "RefLatitude", number) -@step(u'The site "{guid}" has an elevation of "{number}"') +@step('The site "{guid}" has an elevation of "{number}"') def step_impl(context, guid, number): number = util.assert_number(number) site = util.assert_guid(IfcStore.file, guid) @@ -256,7 +256,7 @@ def step_impl(context, guid, number): util.assert_attribute(site, "RefElevation", number) -@step(u'The site "{guid}" must be coincident with the project origin') +@step('The site "{guid}" must be coincident with the project origin') def step_impl(context, guid): site = util.assert_guid(IfcStore.file, guid) util.assert_type(site, "IfcSite") diff --git a/src/ifcbimtester/bimtester/run.py b/src/ifcbimtester/bimtester/run.py index 725c208913..5f0d58bd18 100644 --- a/src/ifcbimtester/bimtester/run.py +++ b/src/ifcbimtester/bimtester/run.py @@ -38,7 +38,6 @@ from behave.__main__ import main as behave_main from logging import StreamHandler - class TestRunner: def __init__(self, ifc_path, schema_path=None, ifc=None): IfcStore.path = ifc_path diff --git a/src/ifcblender/io_import_scene_ifc/__init__.py b/src/ifcblender/io_import_scene_ifc/__init__.py index bc114da232..b005b15564 100644 --- a/src/ifcblender/io_import_scene_ifc/__init__.py +++ b/src/ifcblender/io_import_scene_ifc/__init__.py @@ -163,6 +163,7 @@ def import_ifc(filename, use_names, process_relations, blender_booleans): me.from_pydata(verts, [], faces) me.validate() + # MATERIAL CREATION def add_material(mname, props): if mname in bpy.data.materials: diff --git a/src/ifccityjson/ifccityjson/__main__.py b/src/ifccityjson/ifccityjson/__main__.py index 90361bb894..284560b288 100644 --- a/src/ifccityjson/ifccityjson/__main__.py +++ b/src/ifccityjson/ifccityjson/__main__.py @@ -20,6 +20,7 @@ import argparse from cjio import cityjson from .cityjson2ifc import Cityjson2ifc + def cmdline(): # Example: # python ifccityjson.py -i example/3DBAG_example.json -o example/output.ifc -n identificatie @@ -28,10 +29,10 @@ def cmdline(): parser.add_argument("-i", "--input", type=str, help="input CityJSON file", required=True) parser.add_argument("-o", "--output", type=str, help="output IFC file. Standard is output.ifc") parser.add_argument("-n", "--name", type=str, help="Attribute containing the name") - parser.add_argument('--split-lod', dest='split', action='store_true', - help="Split the file in multiple LoDs") - parser.add_argument('--no-split-lod', dest='split', action='store_false', - help="Do not split the file in multiple LoDs") + parser.add_argument("--split-lod", dest="split", action="store_true", help="Split the file in multiple LoDs") + parser.add_argument( + "--no-split-lod", dest="split", action="store_false", help="Do not split the file in multiple LoDs" + ) parser.add_argument("--lod", type=str, help="extract LOD value (example: 1.2)") parser.set_defaults(split=True) args = parser.parse_args() @@ -50,5 +51,6 @@ def cmdline(): converter.configuration(**data) converter.convert(city_model) -if __name__ == '__main__': + +if __name__ == "__main__": cmdline() diff --git a/src/ifccityjson/ifccityjson/cityjson2ifc/__init__.py b/src/ifccityjson/ifccityjson/cityjson2ifc/__init__.py index 71bcf23e7a..2bfb9dfce1 100644 --- a/src/ifccityjson/ifccityjson/cityjson2ifc/__init__.py +++ b/src/ifccityjson/ifccityjson/cityjson2ifc/__init__.py @@ -16,4 +16,4 @@ # You should have received a copy of the GNU Lesser General Public License # along with ifccityjson. If not, see . __version__ = "0.1.0" -from .cityjson2ifc import * \ No newline at end of file +from .cityjson2ifc import * diff --git a/src/ifcclash/bootstrap.py b/src/ifcclash/bootstrap.py index 15ec2f242a..dc9b028c23 100644 --- a/src/ifcclash/bootstrap.py +++ b/src/ifcclash/bootstrap.py @@ -1,4 +1,3 @@ - # IfcClash - IFC-based clash detection. # Copyright (C) 2020, 2021 Dion Moult # @@ -18,4 +17,3 @@ # along with IfcClash. If not, see . import ifcclash.__main__ - diff --git a/src/ifcclash/make.py b/src/ifcclash/make.py index 1e1f26ee70..b4436f6e14 100644 --- a/src/ifcclash/make.py +++ b/src/ifcclash/make.py @@ -24,4 +24,3 @@ import subprocess cmd = "pyinstaller ./bootstrap.py --name ifcclash --onefile --clean" subprocess.check_output(cmd, shell=True) - diff --git a/src/ifcfm/ifcfm/__main__.py b/src/ifcfm/ifcfm/__main__.py index 6b0fac9cb7..3a34dc245f 100644 --- a/src/ifcfm/ifcfm/__main__.py +++ b/src/ifcfm/ifcfm/__main__.py @@ -11,7 +11,13 @@ parser.add_argument( help="The FM standard to extract. Built-in preset standards include cobie24, cobie3, aohbsem, and basic.", ) parser.add_argument("-i", "--ifc", type=str, required=True, help="The IFC file") -parser.add_argument("-s", "--spreadsheet", type=str, default="output.ods", help="The spreadsheet file, or directory if the format is csv. Defaults to output.ods") +parser.add_argument( + "-s", + "--spreadsheet", + type=str, + default="output.ods", + help="The spreadsheet file, or directory if the format is csv. Defaults to output.ods", +) parser.add_argument( "-f", "--format", type=str, default="ods", help="The format, chosen from csv, ods, or xlsx. Defaults to ods." ) diff --git a/src/ifcpatch/ifcpatch/recipes/FixRevitTINs.py b/src/ifcpatch/ifcpatch/recipes/FixRevitTINs.py index 5f5c031bf6..a7bfb7fb36 100644 --- a/src/ifcpatch/ifcpatch/recipes/FixRevitTINs.py +++ b/src/ifcpatch/ifcpatch/recipes/FixRevitTINs.py @@ -100,7 +100,7 @@ class Patcher: if face.normal.z < 0.5: faces_to_delete.append(face) - bmesh.ops.delete(bm, geom=faces_to_delete, context='FACES_ONLY') + bmesh.ops.delete(bm, geom=faces_to_delete, context="FACES_ONLY") bmesh.ops.remove_doubles(bm, verts=bm.verts, dist=0.01) bmesh.ops.triangulate(bm, faces=bm.faces[:], quad_method="BEAUTY", ngon_method="BEAUTY") diff --git a/src/ifcpatch/test/test_MergeProject.py b/src/ifcpatch/test/test_MergeProject.py index dabbf1ce1b..c190a4d05a 100644 --- a/src/ifcpatch/test/test_MergeProject.py +++ b/src/ifcpatch/test/test_MergeProject.py @@ -119,8 +119,8 @@ class TestMergeProject(test.bootstrap.IFC4): ifcopenshell.api.geometry.assign_representation(self.file, product=wall1, representation=rep) shape = ifcopenshell.geom.create_shape(ifcopenshell.geom.settings(), wall1) verts = ifcopenshell.util.shape.get_shape_vertices(shape, shape.geometry) - assert np.any(np.all(np.isclose(np.array((1., 2., 3.)), verts), axis=1)) - assert np.any(np.all(np.isclose(np.array((3., 4., 5.)), verts), axis=1)) + assert np.any(np.all(np.isclose(np.array((1.0, 2.0, 3.0)), verts), axis=1)) + assert np.any(np.all(np.isclose(np.array((3.0, 4.0, 5.0)), verts), axis=1)) # Second file is in millimeters with a different false origin wall1 = second_file.by_type("IfcWall")[0] @@ -134,8 +134,8 @@ class TestMergeProject(test.bootstrap.IFC4): ifcopenshell.api.geometry.assign_representation(second_file, product=wall1, representation=rep) shape = ifcopenshell.geom.create_shape(ifcopenshell.geom.settings(), wall1) verts = ifcopenshell.util.shape.get_shape_vertices(shape, shape.geometry) - assert np.any(np.all(np.isclose(np.array((1., 2., 3.)), verts), axis=1)) - assert np.any(np.all(np.isclose(np.array((3., 4., 5.)), verts), axis=1)) + assert np.any(np.all(np.isclose(np.array((1.0, 2.0, 3.0)), verts), axis=1)) + assert np.any(np.all(np.isclose(np.array((3.0, 4.0, 5.0)), verts), axis=1)) output = ifcpatch.execute({"file": self.file, "recipe": "MergeProject", "arguments": [second_file]}) @@ -155,17 +155,17 @@ class TestMergeProject(test.bootstrap.IFC4): m2 = ifcopenshell.util.placement.get_local_placement(wall2.ObjectPlacement) assert np.allclose(m1[:, 3], (1, 2, 3, 1)) # assert np.allclose(m2[:, 3], (8.321, 29.321, 3, 1), atol=1e-3) - assert np.allclose(m2[:, 3], (17.847, 24.707, 3., 1.), atol=1e-3) + assert np.allclose(m2[:, 3], (17.847, 24.707, 3.0, 1.0), atol=1e-3) shape = ifcopenshell.geom.create_shape(ifcopenshell.geom.settings(), wall1) verts = ifcopenshell.util.shape.get_shape_vertices(shape, shape.geometry) - assert np.any(np.all(np.isclose(np.array((1., 2., 3.)), verts), axis=1)) - assert np.any(np.all(np.isclose(np.array((3., 4., 5.)), verts), axis=1)) + assert np.any(np.all(np.isclose(np.array((1.0, 2.0, 3.0)), verts), axis=1)) + assert np.any(np.all(np.isclose(np.array((3.0, 4.0, 5.0)), verts), axis=1)) shape = ifcopenshell.geom.create_shape(ifcopenshell.geom.settings(), wall2) verts = ifcopenshell.util.shape.get_shape_vertices(shape, shape.geometry) - assert np.any(np.all(np.isclose(np.array((17.847, 24.707, 3.)), verts, atol=1e-3), axis=1)) - assert np.any(np.all(np.isclose(np.array((20.410, 25.902, 5.)), verts, atol=1e-3), axis=1)) + assert np.any(np.all(np.isclose(np.array((17.847, 24.707, 3.0)), verts, atol=1e-3), axis=1)) + assert np.any(np.all(np.isclose(np.array((20.410, 25.902, 5.0)), verts, atol=1e-3), axis=1)) class TestMergeProjectIFC2X3(test.bootstrap.IFC2X3, TestMergeProject): diff --git a/src/ifcsverchok/nodes/ifc/add_pset.py b/src/ifcsverchok/nodes/ifc/add_pset.py index e71e5961af..73f5e24d37 100644 --- a/src/ifcsverchok/nodes/ifc/add_pset.py +++ b/src/ifcsverchok/nodes/ifc/add_pset.py @@ -55,9 +55,9 @@ class SvIfcAddPset(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.helper.SvIf self.outputs.new("SvStringsSocket", "Entity") def draw_buttons(self, context, layout): - layout.operator( - "node.sv_ifc_tooltip", text="", icon="QUESTION", emboss=False - ).tooltip = "Add a property set and corresponding properties to IfcElements." + layout.operator("node.sv_ifc_tooltip", text="", icon="QUESTION", emboss=False).tooltip = ( + "Add a property set and corresponding properties to IfcElements." + ) def process(self): if not any(socket.is_linked for socket in self.outputs): @@ -83,9 +83,7 @@ class SvIfcAddPset(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.helper.SvIf def create(self, name, properties, elements): results = [] for element in elements: - result = ifcopenshell.api.run( - "pset.add_pset", self.file, product=element, name=name - ) + result = ifcopenshell.api.run("pset.add_pset", self.file, product=element, name=name) ifcopenshell.api.run( "pset.edit_pset", self.file, diff --git a/src/ifcsverchok/nodes/ifc/api.py b/src/ifcsverchok/nodes/ifc/api.py index cf9784c31b..7429c8ac58 100644 --- a/src/ifcsverchok/nodes/ifc/api.py +++ b/src/ifcsverchok/nodes/ifc/api.py @@ -24,7 +24,8 @@ from bpy.props import StringProperty, EnumProperty from sverchok.node_tree import SverchCustomTreeNode from sverchok.data_structure import updateNode import logging -logger = logging.getLogger('sverchok.ifc') + +logger = logging.getLogger("sverchok.ifc") def update_usecase(self, context): diff --git a/src/ifcsverchok/nodes/ifc/bmesh_to_ifc.py b/src/ifcsverchok/nodes/ifc/bmesh_to_ifc.py index 054171ca46..0b8afcbeb3 100644 --- a/src/ifcsverchok/nodes/ifc/bmesh_to_ifc.py +++ b/src/ifcsverchok/nodes/ifc/bmesh_to_ifc.py @@ -42,9 +42,7 @@ from sverchok.core.socket_data import sv_get_socket from itertools import chain, cycle -class SvIfcBMeshToIfcRepr( - bpy.types.Node, SverchCustomTreeNode, ifcsverchok.helper.SvIfcCore -): +class SvIfcBMeshToIfcRepr(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.helper.SvIfcCore): """ Triggers: BMesh to Ifc Repr Tooltip: Blender mesh to Ifc Shape Representation @@ -61,9 +59,7 @@ class SvIfcBMeshToIfcRepr( self.process() self.refresh_local = False - refresh_local: BoolProperty( - name="Update Node", description="Update Node", update=refresh_node - ) + refresh_local: BoolProperty(name="Update Node", description="Update Node", update=refresh_node) context_types = [ ("Model", "Model", "Context type: Model", 0), @@ -113,20 +109,16 @@ class SvIfcBMeshToIfcRepr( def sv_init(self, context): self.inputs.new("SvStringsSocket", "context_type").prop_name = "context_type" - self.inputs.new( - "SvStringsSocket", "context_identifier" - ).prop_name = "context_identifier" + self.inputs.new("SvStringsSocket", "context_identifier").prop_name = "context_identifier" self.inputs.new("SvStringsSocket", "target_view").prop_name = "target_view" - self.inputs.new( - "SvObjectSocket", "blender_objects" - ).prop_name = "blender_objects" # no prop for now + self.inputs.new("SvObjectSocket", "blender_objects").prop_name = "blender_objects" # no prop for now self.outputs.new("SvVerticesSocket", "Representations") self.outputs.new("SvMatrixSocket", "Locations") def draw_buttons(self, context, layout): - layout.operator( - "node.sv_ifc_tooltip", text="", icon="QUESTION", emboss=False - ).tooltip = "Blender mesh to Ifc Shape Representation. \nTakes one or multiple geometries.\nDeconstructs joined geometries and creates a separate representation for each." + layout.operator("node.sv_ifc_tooltip", text="", icon="QUESTION", emboss=False).tooltip = ( + "Blender mesh to Ifc Shape Representation. \nTakes one or multiple geometries.\nDeconstructs joined geometries and creates a separate representation for each." + ) row = layout.row(align=True) row.prop(self, "is_interactive", icon="SCENE_DATA", icon_only=True) @@ -136,9 +128,7 @@ class SvIfcBMeshToIfcRepr( self.sv_input_names = [i.name for i in self.inputs] if hash(self) not in self.node_dict: - self.node_dict[ - hash(self) - ] = {} # happens if node is already on canvas when blender loads + self.node_dict[hash(self)] = {} # happens if node is already on canvas when blender loads if not self.node_dict[hash(self)]: self.node_dict[hash(self)].update(dict.fromkeys(self.sv_input_names, 0)) @@ -211,21 +201,17 @@ class SvIfcBMeshToIfcRepr( context=context, ) if not representation: - raise Exception( - "Couldn't create representation. Possibly wrong context." - ) + raise Exception("Couldn't create representation. Possibly wrong context.") representations_ids_obj.append([representation.id()]) locations_obj.append([obj.matrix_world]) representations_ids.append(representations_ids_obj) locations.append(locations_obj) - SvIfcStore.id_map.setdefault(self.node_id, {}).setdefault( - "Representations", [] - ).append(representations_ids_obj) - SvIfcStore.id_map.setdefault(self.node_id, {}).setdefault( - "Locations", [] - ).append(locations_obj) + SvIfcStore.id_map.setdefault(self.node_id, {}).setdefault("Representations", []).append( + representations_ids_obj + ) + SvIfcStore.id_map.setdefault(self.node_id, {}).setdefault("Locations", []).append(locations_obj) bpy.ops.object.select_all(action="DESELECT") return representations_ids, locations @@ -248,13 +234,9 @@ class SvIfcBMeshToIfcRepr( self.file, self.context_type, self.context_identifier, self.target_view ) if not context: - parent = ifcopenshell.util.representation.get_context( - self.file, self.context_type - ) + parent = ifcopenshell.util.representation.get_context(self.file, self.context_type) if not parent: - parent = ifcopenshell.api.run( - "context.add_context", self.file, context_type=self.context_type - ) + parent = ifcopenshell.api.run("context.add_context", self.file, context_type=self.context_type) context = ifcopenshell.api.run( "context.add_context", self.file, @@ -263,9 +245,7 @@ class SvIfcBMeshToIfcRepr( target_view=self.target_view, parent=parent, ) - SvIfcStore.id_map.setdefault(self.node_id, {}).setdefault( - "Contexts", [] - ).append(context.id()) + SvIfcStore.id_map.setdefault(self.node_id, {}).setdefault("Contexts", []).append(context.id()) return context def sv_free(self): @@ -286,14 +266,10 @@ class SvIfcBMeshToIfcRepr( if not self.file.get_inverse(context): if self.file.by_id(context_id).ParentContext: parent = self.file.by_id(context_id).ParentContext - ifcopenshell.api.run( - "context.remove_context", self.file, context=context - ) + ifcopenshell.api.run("context.remove_context", self.file, context=context) if parent: if not self.file.get_inverse(parent): - ifcopenshell.api.run( - "context.remove_context", self.file, context=parent - ) + ifcopenshell.api.run("context.remove_context", self.file, context=parent) SvIfcStore.id_map[self.node_id]["Contexts"].remove(context_id) del SvIfcStore.id_map[self.node_id] del self.node_dict[hash(self)] diff --git a/src/ifcsverchok/nodes/ifc/by_guid.py b/src/ifcsverchok/nodes/ifc/by_guid.py index aa8b0b2177..65c5196fad 100644 --- a/src/ifcsverchok/nodes/ifc/by_guid.py +++ b/src/ifcsverchok/nodes/ifc/by_guid.py @@ -39,9 +39,9 @@ class SvIfcByGuid(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.helper.SvIfc self.outputs.new("SvStringsSocket", "Entities") def draw_buttons(self, context, layout): - layout.operator( - "node.sv_ifc_tooltip", text="", icon="QUESTION", emboss=False - ).tooltip = "Get IFC element by guid. Takes one or multiple guids." + layout.operator("node.sv_ifc_tooltip", text="", icon="QUESTION", emboss=False).tooltip = ( + "Get IFC element by guid. Takes one or multiple guids." + ) def process(self): self.guids = flatten_data(self.inputs["guid"].sv_get(), target_level=1) diff --git a/src/ifcsverchok/nodes/ifc/by_id.py b/src/ifcsverchok/nodes/ifc/by_id.py index edc40a19a1..b42060fcf5 100644 --- a/src/ifcsverchok/nodes/ifc/by_id.py +++ b/src/ifcsverchok/nodes/ifc/by_id.py @@ -38,9 +38,9 @@ class SvIfcById(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.helper.SvIfcCo self.outputs.new("SvStringsSocket", "Entities") def draw_buttons(self, context, layout): - layout.operator( - "node.sv_ifc_tooltip", text="", icon="QUESTION", emboss=False - ).tooltip = "Get IFC element by step id. Takes one or multiple step ids." + layout.operator("node.sv_ifc_tooltip", text="", icon="QUESTION", emboss=False).tooltip = ( + "Get IFC element by step id. Takes one or multiple step ids." + ) def process(self): self.ids = flatten_data(self.inputs["id"].sv_get(), target_level=1) diff --git a/src/ifcsverchok/nodes/ifc/by_type.py b/src/ifcsverchok/nodes/ifc/by_type.py index 15c500142d..96c9d84942 100644 --- a/src/ifcsverchok/nodes/ifc/by_type.py +++ b/src/ifcsverchok/nodes/ifc/by_type.py @@ -108,17 +108,15 @@ class SvIfcByType(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.helper.SvIfc def sv_init(self, context): self.inputs.new("SvStringsSocket", "ifc_product").prop_name = "ifc_product" self.inputs.new("SvStringsSocket", "ifc_class").prop_name = "ifc_class" - self.inputs.new( - "SvStringsSocket", "custom_ifc_class" - ).prop_name = "custom_ifc_class" + self.inputs.new("SvStringsSocket", "custom_ifc_class").prop_name = "custom_ifc_class" self.outputs.new("SvStringsSocket", "Entities") self.outputs.new("SvStringsSocket", "Entity Ids") self.width = 200 def draw_buttons(self, context, layout): - layout.operator( - "node.sv_ifc_tooltip", text="", icon="QUESTION", emboss=False - ).tooltip = "Get IFC element(s) in file by type. \nPick an IfcProduct and an IfcClass or give a custom IfcClass." + layout.operator("node.sv_ifc_tooltip", text="", icon="QUESTION", emboss=False).tooltip = ( + "Get IFC element(s) in file by type. \nPick an IfcProduct and an IfcClass or give a custom IfcClass." + ) def process(self): self.file = SvIfcStore.get_file() diff --git a/src/ifcsverchok/nodes/ifc/create_entity.py b/src/ifcsverchok/nodes/ifc/create_entity.py index 6843336c61..f17b02a3c0 100644 --- a/src/ifcsverchok/nodes/ifc/create_entity.py +++ b/src/ifcsverchok/nodes/ifc/create_entity.py @@ -32,9 +32,7 @@ from sverchok.data_structure import ( ) -class SvIfcCreateEntity( - bpy.types.Node, SverchCustomTreeNode, ifcsverchok.helper.SvIfcCore -): +class SvIfcCreateEntity(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.helper.SvIfcCore): bl_idname = "SvIfcCreateEntity" bl_label = "IFC Create Entity" node_dict = {} @@ -46,9 +44,7 @@ class SvIfcCreateEntity( self.process() self.refresh_local = False - refresh_local: BoolProperty( - name="Update Node", description="Update Node", update=refresh_node - ) + refresh_local: BoolProperty(name="Update Node", description="Update Node", update=refresh_node) Names: StringProperty( name="Names", @@ -76,18 +72,16 @@ class SvIfcCreateEntity( self.inputs.new("SvStringsSocket", "Names").prop_name = "Names" self.inputs.new("SvStringsSocket", "Descriptions").prop_name = "Descriptions" self.inputs.new("SvStringsSocket", "IfcClass").prop_name = "IfcClass" - self.inputs.new( - "SvStringsSocket", "Representations" - ).prop_name = "Representations" + self.inputs.new("SvStringsSocket", "Representations").prop_name = "Representations" self.inputs.new("SvMatrixSocket", "Locations").is_mandatory = False # self.inputs.new("SvStringsSocket", "Properties").prop_name = "Properties" self.outputs.new("SvStringsSocket", "Entities") self.node_dict[hash(self)] = {} def draw_buttons(self, context, layout): - layout.operator( - "node.sv_ifc_tooltip", text="", icon="QUESTION", emboss=False - ).tooltip = "Create IFC Entity. Takes one or multiple inputs. \nIf 'Representation(s)' is given, that determines number of output entities. Otherwise, 'Names' is used." + layout.operator("node.sv_ifc_tooltip", text="", icon="QUESTION", emboss=False).tooltip = ( + "Create IFC Entity. Takes one or multiple inputs. \nIf 'Representation(s)' is given, that determines number of output entities. Otherwise, 'Names' is used." + ) row = layout.row(align=True) row.prop(self, "is_interactive", icon="SCENE_DATA", icon_only=True) @@ -95,26 +89,16 @@ class SvIfcCreateEntity( def process(self): self.names = flatten_data(self.inputs["Names"].sv_get(), target_level=1) - self.descriptions = flatten_data( - self.inputs["Descriptions"].sv_get(), target_level=1 - ) - self.ifc_class = flatten_data(self.inputs["IfcClass"].sv_get(), target_level=1)[ - 0 - ] - self.representations = ensure_min_nesting( - self.inputs["Representations"].sv_get(), 3 - ) + self.descriptions = flatten_data(self.inputs["Descriptions"].sv_get(), target_level=1) + self.ifc_class = flatten_data(self.inputs["IfcClass"].sv_get(), target_level=1)[0] + self.representations = ensure_min_nesting(self.inputs["Representations"].sv_get(), 3) self.representations = flatten_data(self.representations, target_level=3) - self.locations = ensure_min_nesting( - self.inputs["Locations"].sv_get(default=[]), 3 - ) + self.locations = ensure_min_nesting(self.inputs["Locations"].sv_get(default=[]), 3) self.locations = flatten_data(self.locations, target_level=3) self.sv_input_names = [i.name for i in self.inputs] if hash(self) not in self.node_dict: - self.node_dict[ - hash(self) - ] = {} # happens if node is already on canvas when blender loads + self.node_dict[hash(self)] = {} # happens if node is already on canvas when blender loads if not self.node_dict[hash(self)]: self.node_dict[hash(self)].update(dict.fromkeys(self.sv_input_names, 0)) if not self.inputs["IfcClass"].sv_get()[0][0]: @@ -122,9 +106,7 @@ class SvIfcCreateEntity( edit = False for i in range(len(self.inputs)): - input = self.inputs[self.sv_input_names[i]].sv_get( - deepcopy=True, default=[] - ) + input = self.inputs[self.sv_input_names[i]].sv_get(deepcopy=True, default=[]) if ( isinstance(self.node_dict[hash(self)][self.inputs[i].name], list) and input != self.node_dict[hash(self)][self.inputs[i].name] @@ -142,27 +124,18 @@ class SvIfcCreateEntity( for group in self.representations: try: group_representations = [ - [self.file.by_id(step_id) for step_id in representation] - for representation in group + [self.file.by_id(step_id) for step_id in representation] for representation in group ] representations.append(group_representations) except Exception as e: raise - names.append( - self.repeat_input_unique(self.names, len(group_representations)) - ) - descriptions.append( - self.repeat_input_unique( - self.descriptions, len(group_representations) - ) - ) + names.append(self.repeat_input_unique(self.names, len(group_representations))) + descriptions.append(self.repeat_input_unique(self.descriptions, len(group_representations))) self.representations = representations self.names = names self.descriptions = descriptions elif not self.representations[0][0][0]: - self.descriptions = self.repeat_input_unique( - self.descriptions, len(self.names) - ) + self.descriptions = self.repeat_input_unique(self.descriptions, len(self.names)) self.names = ensure_min_nesting(self.names, 2) self.descriptions = ensure_min_nesting(self.descriptions, 2) if self.node_id not in SvIfcStore.id_map: @@ -193,7 +166,7 @@ class SvIfcCreateEntity( self.file, ifc_class=self.ifc_class, name=self.names[i][j], - #description=self.descriptions[i][j], + # description=self.descriptions[i][j], ) try: for repr in self.representations[i][j]: @@ -266,9 +239,7 @@ class SvIfcCreateEntity( pass if entity.is_a() != self.ifc_class: SvIfcStore.id_map[self.node_id][i].remove(step_id) - entity = ifcopenshell.util.schema.reassign_class( - self.file, entity, self.ifc_class - ) + entity = ifcopenshell.util.schema.reassign_class(self.file, entity, self.ifc_class) group_entities_ids.append(entity.id()) entities_ids.append(group_entities_ids) @@ -280,12 +251,10 @@ class SvIfcCreateEntity( if input[0]: if flag: return [ - [a] if not (s := sum(j == a for j in input[:i])) else [f"{a}-{s+1}"] - for i, a in enumerate(input) + [a] if not (s := sum(j == a for j in input[:i])) else [f"{a}-{s+1}"] for i, a in enumerate(input) ] input = [ - a if not (s := sum(j == a for j in input[:i])) else f"{a}-{s+1}" - for i, a in enumerate(input) + a if not (s := sum(j == a for j in input[:i])) else f"{a}-{s+1}" for i, a in enumerate(input) ] # add number to duplicates return input diff --git a/src/ifcsverchok/nodes/ifc/create_project.py b/src/ifcsverchok/nodes/ifc/create_project.py index 3f8b323e51..3048f7f936 100644 --- a/src/ifcsverchok/nodes/ifc/create_project.py +++ b/src/ifcsverchok/nodes/ifc/create_project.py @@ -35,9 +35,9 @@ class SvIfcCreateProject(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.helpe self.outputs.new("SvVerticesSocket", "file") def draw_buttons(self, context, layout): - op = layout.operator( - "node.sv_ifc_tooltip", text="", icon="QUESTION", emboss=False - ).tooltip = "Adds project, unit and context to IFC file" + op = layout.operator("node.sv_ifc_tooltip", text="", icon="QUESTION", emboss=False).tooltip = ( + "Adds project, unit and context to IFC file" + ) # op.tooltip = self.tooltip def process(self): diff --git a/src/ifcsverchok/nodes/ifc/create_shape.py b/src/ifcsverchok/nodes/ifc/create_shape.py index bfcc971b51..8fe5b63d73 100644 --- a/src/ifcsverchok/nodes/ifc/create_shape.py +++ b/src/ifcsverchok/nodes/ifc/create_shape.py @@ -54,9 +54,9 @@ class SvIfcCreateShape(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.helper. def draw_buttons(self, context, layout): row = layout.row(align=True) - row.operator( - "node.sv_ifc_tooltip", text="", icon="QUESTION", emboss=False - ).tooltip = "Create Blender shape from IfcEntity Id. Takes one or multiple IfcEntity IDs." + row.operator("node.sv_ifc_tooltip", text="", icon="QUESTION", emboss=False).tooltip = ( + "Create Blender shape from IfcEntity Id. Takes one or multiple IfcEntity IDs." + ) row.prop(self, "refresh_local", icon="FILE_REFRESH") def process(self): diff --git a/src/ifcsverchok/nodes/ifc/get_attribute.py b/src/ifcsverchok/nodes/ifc/get_attribute.py index 3e7a343c10..c4ec65e30e 100644 --- a/src/ifcsverchok/nodes/ifc/get_attribute.py +++ b/src/ifcsverchok/nodes/ifc/get_attribute.py @@ -26,9 +26,7 @@ from sverchok.node_tree import SverchCustomTreeNode from sverchok.data_structure import updateNode, flatten_data -class SvIfcGetAttribute( - bpy.types.Node, SverchCustomTreeNode, ifcsverchok.helper.SvIfcCore -): +class SvIfcGetAttribute(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.helper.SvIfcCore): bl_idname = "SvIfcGetAttribute" bl_label = "IFC Get Attribute" entity: StringProperty(name="Entity Ids", update=updateNode) @@ -40,30 +38,22 @@ class SvIfcGetAttribute( def sv_init(self, context): self.inputs.new("SvStringsSocket", "entity").prop_name = "entity" - self.inputs.new( - "SvStringsSocket", "attribute_name" - ).prop_name = "attribute_name" + self.inputs.new("SvStringsSocket", "attribute_name").prop_name = "attribute_name" self.outputs.new("SvStringsSocket", "value") def draw_buttons(self, context, layout): - layout.operator( - "node.sv_ifc_tooltip", text="", icon="QUESTION", emboss=False - ).tooltip = ( + layout.operator("node.sv_ifc_tooltip", text="", icon="QUESTION", emboss=False).tooltip = ( "Get the value of an attribute of an IfcEntity. Can take multiple entities." ) def process(self): self.value_out = [] - entity_nested_input_ids = flatten_data( - self.inputs["entity"].sv_get(), target_level=1 - ) + entity_nested_input_ids = flatten_data(self.inputs["entity"].sv_get(), target_level=1) if not entity_nested_input_ids[0]: return self.file = SvIfcStore.get_file() try: - entity_nested_inputs = [ - self.file.by_id(int(step_id)) for step_id in entity_nested_input_ids - ] + entity_nested_inputs = [self.file.by_id(int(step_id)) for step_id in entity_nested_input_ids] except Exception as e: raise Exception("Instance ID not found", e) attribute_name = self.inputs["attribute_name"].sv_get()[0][0] diff --git a/src/ifcsverchok/nodes/ifc/get_property.py b/src/ifcsverchok/nodes/ifc/get_property.py index 47afde3862..a9a78e15b9 100644 --- a/src/ifcsverchok/nodes/ifc/get_property.py +++ b/src/ifcsverchok/nodes/ifc/get_property.py @@ -26,9 +26,7 @@ from sverchok.node_tree import SverchCustomTreeNode from sverchok.data_structure import updateNode, flatten_data -class SvIfcGetProperty( - bpy.types.Node, SverchCustomTreeNode, ifcsverchok.helper.SvIfcCore -): +class SvIfcGetProperty(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.helper.SvIfcCore): bl_idname = "SvIfcGetProperty" bl_label = "IFC Get Property" entity: StringProperty(name="Entity Ids", update=updateNode) @@ -50,9 +48,7 @@ class SvIfcGetProperty( self.outputs.new("SvStringsSocket", "value") def draw_buttons(self, context, layout): - layout.operator( - "node.sv_ifc_tooltip", text="", icon="QUESTION", emboss=False - ).tooltip = ( + layout.operator("node.sv_ifc_tooltip", text="", icon="QUESTION", emboss=False).tooltip = ( "Get the value of a property of an IfcEntity. Can take multiple entity ids." ) @@ -72,9 +68,7 @@ class SvIfcGetProperty( self.value_out = [] for entity in self.entities: try: - self.value_out.append( - ifcopenshell.util.element.get_psets(entity)[pset_name][prop_name] - ) + self.value_out.append(ifcopenshell.util.element.get_psets(entity)[pset_name][prop_name]) except: pass self.outputs["value"].sv_set(self.value_out) diff --git a/src/ifcsverchok/nodes/ifc/quick_project_setup.py b/src/ifcsverchok/nodes/ifc/quick_project_setup.py index 435f8150bb..696d6d6515 100644 --- a/src/ifcsverchok/nodes/ifc/quick_project_setup.py +++ b/src/ifcsverchok/nodes/ifc/quick_project_setup.py @@ -60,9 +60,9 @@ class SvIfcQuickProjectSetup(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.h self.outputs.new("SvVerticesSocket", "file") def draw_buttons(self, context, layout): - op = layout.operator( - "node.sv_ifc_tooltip", text="", icon="QUESTION", emboss=False - ).tooltip = "Quick Project Setup: creates Ifc file and sets up a basic project" + op = layout.operator("node.sv_ifc_tooltip", text="", icon="QUESTION", emboss=False).tooltip = ( + "Quick Project Setup: creates Ifc file and sets up a basic project" + ) # op.tooltip = self.tooltip def process(self): diff --git a/src/ifcsverchok/nodes/ifc/read_entity.py b/src/ifcsverchok/nodes/ifc/read_entity.py index 919e740e73..fb581d1b63 100644 --- a/src/ifcsverchok/nodes/ifc/read_entity.py +++ b/src/ifcsverchok/nodes/ifc/read_entity.py @@ -25,9 +25,7 @@ from sverchok.node_tree import SverchCustomTreeNode from sverchok.data_structure import updateNode, ensure_min_nesting, flatten_data -class SvIfcReadEntity( - bpy.types.Node, SverchCustomTreeNode, ifcsverchok.helper.SvIfcCore -): +class SvIfcReadEntity(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.helper.SvIfcCore): bl_idname = "SvIfcReadEntity" bl_label = "IFC Read Entity" entity: StringProperty(name="Entity Id", update=updateNode) @@ -39,9 +37,7 @@ class SvIfcReadEntity( self.outputs.new("SvStringsSocket", "is_a") def draw_buttons(self, context, layout): - layout.operator( - "node.sv_ifc_tooltip", text="", icon="QUESTION", emboss=False - ).tooltip = ( + layout.operator("node.sv_ifc_tooltip", text="", icon="QUESTION", emboss=False).tooltip = ( "Decompose an IfcEntity into its attributes. Takes one entity id as input" ) diff --git a/src/ifcsverchok/nodes/ifc/sverchok_to_ifc.py b/src/ifcsverchok/nodes/ifc/sverchok_to_ifc.py index 3cc528984b..dfedcf1f4a 100644 --- a/src/ifcsverchok/nodes/ifc/sverchok_to_ifc.py +++ b/src/ifcsverchok/nodes/ifc/sverchok_to_ifc.py @@ -30,9 +30,7 @@ from sverchok.node_tree import SverchCustomTreeNode from sverchok.data_structure import updateNode, ensure_min_nesting -class SvIfcSverchokToIfcRepr( - bpy.types.Node, SverchCustomTreeNode, ifcsverchok.helper.SvIfcCore -): +class SvIfcSverchokToIfcRepr(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.helper.SvIfcCore): """ Triggers: Sv to Ifc Repr Tooltip: Sverchok geometry to Ifc Shape Representation @@ -85,9 +83,7 @@ class SvIfcSverchokToIfcRepr( def sv_init(self, context): self.inputs.new("SvStringsSocket", "context_type").prop_name = "context_type" - self.inputs.new( - "SvStringsSocket", "context_identifier" - ).prop_name = "context_identifier" + self.inputs.new("SvStringsSocket", "context_identifier").prop_name = "context_identifier" self.inputs.new("SvStringsSocket", "target_view").prop_name = "target_view" self.inputs.new("SvVerticesSocket", "Vertices") self.inputs.new("SvStringsSocket", "Edges") @@ -97,9 +93,9 @@ class SvIfcSverchokToIfcRepr( self.node_dict[hash(self)] = {} def draw_buttons(self, context, layout): - op = layout.operator( - "node.sv_ifc_tooltip", text="", icon="QUESTION", emboss=False - ).tooltip = "Sverchok geometry to Ifc Shape Representation. \nTakes one or multiple geometries." + op = layout.operator("node.sv_ifc_tooltip", text="", icon="QUESTION", emboss=False).tooltip = ( + "Sverchok geometry to Ifc Shape Representation. \nTakes one or multiple geometries." + ) def process(self): if not any(socket.is_linked for socket in self.inputs): @@ -108,9 +104,7 @@ class SvIfcSverchokToIfcRepr( self.sv_input_names = [i.name for i in self.inputs] if hash(self) not in self.node_dict: - self.node_dict[ - hash(self) - ] = {} # happens if node is already on canvas when blender loads + self.node_dict[hash(self)] = {} # happens if node is already on canvas when blender loads if not self.node_dict[hash(self)]: self.node_dict[hash(self)].update(dict.fromkeys(self.sv_input_names, 0)) @@ -124,9 +118,7 @@ class SvIfcSverchokToIfcRepr( edit = True self.node_dict[hash(self)][self.inputs[i].name] = input - self.vertices = ensure_min_nesting( - self.inputs["Vertices"].sv_get(deepcopy=False), 4 - ) + self.vertices = ensure_min_nesting(self.inputs["Vertices"].sv_get(deepcopy=False), 4) self.edges = ensure_min_nesting(self.inputs["Edges"].sv_get(deepcopy=False), 4) self.faces = ensure_min_nesting(self.inputs["Faces"].sv_get(deepcopy=False), 4) data = list(zip(self.vertices, self.edges, self.faces)) @@ -160,14 +152,12 @@ class SvIfcSverchokToIfcRepr( faces=[list(map(tuple, item[2]))], ) if not representation: - raise Exception( - "Couldn't create representation. Possibly wrong context." - ) + raise Exception("Couldn't create representation. Possibly wrong context.") representations_ids_obj.append([representation.id()]) representations_ids.append(representations_ids_obj) - SvIfcStore.id_map.setdefault(self.node_id, {}).setdefault( - "Representations", [] - ).append(representations_ids_obj) + SvIfcStore.id_map.setdefault(self.node_id, {}).setdefault("Representations", []).append( + representations_ids_obj + ) return representations_ids def edit(self): @@ -188,13 +178,9 @@ class SvIfcSverchokToIfcRepr( self.file, self.context_type, self.context_identifier, self.target_view ) if not context: - parent = ifcopenshell.util.representation.get_context( - self.file, self.context_type - ) + parent = ifcopenshell.util.representation.get_context(self.file, self.context_type) if not parent: - parent = ifcopenshell.api.run( - "context.add_context", self.file, context_type=self.context_type - ) + parent = ifcopenshell.api.run("context.add_context", self.file, context_type=self.context_type) context = ifcopenshell.api.run( "context.add_context", self.file, @@ -203,9 +189,7 @@ class SvIfcSverchokToIfcRepr( target_view=self.target_view, parent=parent, ) - SvIfcStore.id_map.setdefault(self.node_id, {}).setdefault( - "Contexts", [] - ).append(context.id()) + SvIfcStore.id_map.setdefault(self.node_id, {}).setdefault("Contexts", []).append(context.id()) return context def sv_free(self): @@ -225,14 +209,10 @@ class SvIfcSverchokToIfcRepr( if not self.file.get_inverse(context): if self.file.by_id(context_id).ParentContext: parent = self.file.by_id(context_id).ParentContext - ifcopenshell.api.run( - "context.remove_context", self.file, context=context - ) + ifcopenshell.api.run("context.remove_context", self.file, context=context) if parent: if not self.file.get_inverse(parent): - ifcopenshell.api.run( - "context.remove_context", self.file, context=parent - ) + ifcopenshell.api.run("context.remove_context", self.file, context=parent) # print("Removed context with step ID: ", context_id) SvIfcStore.id_map[self.node_id]["Contexts"].remove(context_id) del SvIfcStore.id_map[self.node_id] diff --git a/src/ifctester/ifctester/__init__.py b/src/ifctester/ifctester/__init__.py index 2cc1599de4..edb1db90e4 100644 --- a/src/ifctester/ifctester/__init__.py +++ b/src/ifctester/ifctester/__init__.py @@ -17,4 +17,5 @@ # along with IfcTester. If not, see . from .ids import open + __version__ = version = "0.0.0" diff --git a/src/ifctester/ifctester/__main__.py b/src/ifctester/ifctester/__main__.py index 30d1db517d..a61e2e0b7d 100644 --- a/src/ifctester/ifctester/__main__.py +++ b/src/ifctester/ifctester/__main__.py @@ -27,18 +27,10 @@ from . import reporter parser = argparse.ArgumentParser(description="Uses an IDS to audit an IFC") parser.add_argument("ids", type=str, help="Path to an IDS") parser.add_argument("ifc", type=str, help="Path to an IFC", nargs="?") -parser.add_argument( - "-r", "--reporter", type=str, help="The reporting method to view audit results", default="Console" -) -parser.add_argument( - "--no-color", help="Disable colour output (supported by Console reporting)", action="store_true" -) -parser.add_argument( - "--excel-safe", help="Make sure exported ODS is safely exported for Excel", action="store_true" -) -parser.add_argument( - "-o", "--output", help="Output file (supported for all types of reporting except Console)" -) +parser.add_argument("-r", "--reporter", type=str, help="The reporting method to view audit results", default="Console") +parser.add_argument("--no-color", help="Disable colour output (supported by Console reporting)", action="store_true") +parser.add_argument("--excel-safe", help="Make sure exported ODS is safely exported for Excel", action="store_true") +parser.add_argument("-o", "--output", help="Output file (supported for all types of reporting except Console)") args = parser.parse_args() specs = ids.open(args.ids) diff --git a/src/ifctester/ifctester/reporter.py b/src/ifctester/ifctester/reporter.py index db4b7b5e90..779d3376e7 100644 --- a/src/ifctester/ifctester/reporter.py +++ b/src/ifctester/ifctester/reporter.py @@ -444,7 +444,6 @@ class Html(Json): requirement["total_omitted_passes"] = total_passed_entities - entity_limit requirement["has_omitted_passes"] = total_passed_entities > entity_limit - def to_string(self) -> str: import pystache diff --git a/src/opencdeserver/api/app/api/bcf.py b/src/opencdeserver/api/app/api/bcf.py index 802bd51b70..30d0d5135c 100644 --- a/src/opencdeserver/api/app/api/bcf.py +++ b/src/opencdeserver/api/app/api/bcf.py @@ -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 diff --git a/src/opencdeserver/api/app/api/documents.py b/src/opencdeserver/api/app/api/documents.py index 9db65bfacd..2f568fd9a3 100644 --- a/src/opencdeserver/api/app/api/documents.py +++ b/src/opencdeserver/api/app/api/documents.py @@ -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 diff --git a/src/opencdeserver/api/app/api/foundation.py b/src/opencdeserver/api/app/api/foundation.py index 04a0baa9f4..25c6036ac8 100644 --- a/src/opencdeserver/api/app/api/foundation.py +++ b/src/opencdeserver/api/app/api/foundation.py @@ -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= -@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 diff --git a/src/opencdeserver/api/app/api/logging.py b/src/opencdeserver/api/app/api/logging.py index 2547ac66c2..8090ae9c7d 100644 --- a/src/opencdeserver/api/app/api/logging.py +++ b/src/opencdeserver/api/app/api/logging.py @@ -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) diff --git a/src/opencdeserver/api/app/api/user.py b/src/opencdeserver/api/app/api/user.py index 28d3aa5fbb..5628a4cf05 100644 --- a/src/opencdeserver/api/app/api/user.py +++ b/src/opencdeserver/api/app/api/user.py @@ -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') \ No newline at end of file + file_location = "./data/documents/" + document_id + ".ifc" + return FileResponse( + file_location, media_type="application/x-step", filename="6dbd4d52-14db-11ee-be56-0242ac120002.ifc" + ) diff --git a/src/opencdeserver/api/app/database/neo4j.py b/src/opencdeserver/api/app/database/neo4j.py index a3770d23a7..b6172e7890 100644 --- a/src/opencdeserver/api/app/database/neo4j.py +++ b/src/opencdeserver/api/app/database/neo4j.py @@ -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() diff --git a/src/opencdeserver/api/app/ifcgraph/ifcgraph.py b/src/opencdeserver/api/app/ifcgraph/ifcgraph.py index d88359672a..74f27babd7 100644 --- a/src/opencdeserver/api/app/ifcgraph/ifcgraph.py +++ b/src/opencdeserver/api/app/ifcgraph/ifcgraph.py @@ -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 diff --git a/src/opencdeserver/api/app/main.py b/src/opencdeserver/api/app/main.py index 5240019f4b..4862106a55 100644 --- a/src/opencdeserver/api/app/main.py +++ b/src/opencdeserver/api/app/main.py @@ -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) diff --git a/src/opencdeserver/api/app/models/bcf_common.py b/src/opencdeserver/api/app/models/bcf_common.py index 1227b886c9..e729393506 100644 --- a/src/opencdeserver/api/app/models/bcf_common.py +++ b/src/opencdeserver/api/app/models/bcf_common.py @@ -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): diff --git a/src/opencdeserver/api/app/models/bcf_response.py b/src/opencdeserver/api/app/models/bcf_response.py index c4e39eed62..2b54ce014a 100644 --- a/src/opencdeserver/api/app/models/bcf_response.py +++ b/src/opencdeserver/api/app/models/bcf_response.py @@ -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) diff --git a/src/opencdeserver/api/app/models/documents_common.py b/src/opencdeserver/api/app/models/documents_common.py index ac67e3f111..91db18849a 100644 --- a/src/opencdeserver/api/app/models/documents_common.py +++ b/src/opencdeserver/api/app/models/documents_common.py @@ -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]] diff --git a/src/opencdeserver/api/app/models/documents_other.py b/src/opencdeserver/api/app/models/documents_other.py index bc848dfa6b..bb721c6b27 100644 --- a/src/opencdeserver/api/app/models/documents_other.py +++ b/src/opencdeserver/api/app/models/documents_other.py @@ -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"}, } diff --git a/src/opencdeserver/api/app/models/documents_request.py b/src/opencdeserver/api/app/models/documents_request.py index 91ff3c4fb9..0d9fb0551e 100644 --- a/src/opencdeserver/api/app/models/documents_request.py +++ b/src/opencdeserver/api/app/models/documents_request.py @@ -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") diff --git a/src/opencdeserver/api/app/models/documents_response.py b/src/opencdeserver/api/app/models/documents_response.py index 3b60a47dfe..8b4bc308d7 100644 --- a/src/opencdeserver/api/app/models/documents_response.py +++ b/src/opencdeserver/api/app/models/documents_response.py @@ -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] diff --git a/src/opencdeserver/api/app/models/response.py b/src/opencdeserver/api/app/models/response.py index a41e1d9302..22145a4945 100644 --- a/src/opencdeserver/api/app/models/response.py +++ b/src/opencdeserver/api/app/models/response.py @@ -1,4 +1 @@ from pydantic import BaseModel - - - diff --git a/src/opencdeserver/api/app/repository/bcf.py b/src/opencdeserver/api/app/repository/bcf.py index 8c881286ed..bce4ca1c1f 100644 --- a/src/opencdeserver/api/app/repository/bcf.py +++ b/src/opencdeserver/api/app/repository/bcf.py @@ -45,9 +45,7 @@ class BCFDB(MyDB): AND p.project_id = $project_id RETURN p AS project """ - result = tx.run(cypher, - username=current_user.username, - project_id=str(project_id)) + 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.") @@ -69,10 +67,9 @@ class BCFDB(MyDB): 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) + 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.") @@ -93,9 +90,7 @@ class BCFDB(MyDB): AND p.project_id = $project_id RETURN e AS extensions """ - result = tx.run(cypher, - username=current_user.username, - project_id=str(project_id)) + 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.") @@ -117,9 +112,7 @@ class BCFDB(MyDB): 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)) + 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")) @@ -142,10 +135,7 @@ class BCFDB(MyDB): 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)) + 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.") @@ -181,24 +171,26 @@ class BCFDB(MyDB): 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: + 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) + 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.") @@ -230,20 +222,22 @@ class BCFDB(MyDB): 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) + 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.") @@ -265,11 +259,13 @@ class BCFDB(MyDB): 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()) + 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.") @@ -289,10 +285,7 @@ class BCFDB(MyDB): 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 = 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.") @@ -312,35 +305,29 @@ class BCFDB(MyDB): AND p.project_id = $project_id RETURN d AS document """ - results = tx.run(cypher, - username=current_user.username, - project_id=str(project_id)) + 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_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'] + 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 + "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_information = ProjectFileInformation( + **{"display_information": display_information_list, "file": file_get_json} + ) project_file_informations.append(project_file_information) return project_file_informations @@ -406,10 +393,7 @@ class BCFDB(MyDB): 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)) + 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")) @@ -431,10 +415,12 @@ class BCFDB(MyDB): 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)) + 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) @@ -451,15 +437,17 @@ class BCFDB(MyDB): 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) + 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.") @@ -480,14 +468,11 @@ class BCFDB(MyDB): 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)) + 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_json["topic_guid"] = str(topic_id) comment_model = CommentGET(**comment_json) comment_model_list.append(comment_model) return comment_model_list @@ -507,17 +492,19 @@ class BCFDB(MyDB): 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)) + 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_dict["topic_guid"] = str(topic_id) comment = CommentGET(**comment_dict) return comment @@ -529,7 +516,7 @@ class BCFDB(MyDB): 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: + if not hasattr(comment, "guid") or comment.guid is None: this_comment_guid = uuid4() else: this_comment_guid = UUID(comment.guid) @@ -539,26 +526,26 @@ class BCFDB(MyDB): 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)' + 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'): + 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)' + 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 = '' + 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 @@ -576,21 +563,25 @@ class BCFDB(MyDB): 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) + """ % ( + 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.") @@ -600,21 +591,22 @@ class BCFDB(MyDB): 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( + 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)' + 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 = '' + 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 @@ -630,17 +622,21 @@ class BCFDB(MyDB): 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()) + """ % ( + 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.") @@ -662,11 +658,13 @@ class BCFDB(MyDB): 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 = 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.") @@ -678,27 +676,29 @@ class BCFDB(MyDB): @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' + 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) + 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( + self, project_id: UUID, topic_id: UUID, viewpoint: ViewpointPOST, current_user: User + ) -> ViewpointGET: def post_viewpoint_work(tx) -> str: - if hasattr(viewpoint, 'snapshot'): + 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,' + set_snapshot = "v.snapshot = $snapshot, v.snapshot_type = $snapshot_type," else: - snapshot_type = '' + snapshot_type = "" snapshot = False - set_snapshot = '' - cypher_viewpoint = """ + 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 @@ -716,41 +716,51 @@ class BCFDB(MyDB): v.spaces_visible = $spaces_visible, v.space_boundaries_visible = $space_boundaries_visible, v.openings_visible = $openings_visible - """ % set_snapshot + """ + % set_snapshot + ) if viewpoint.guid is None: viewpoint.guid = uuid4() if viewpoint.orthogonal_camera is None: - camera_definition = 'perspective_camera' + 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' + 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) + 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) @@ -765,10 +775,16 @@ class BCFDB(MyDB): 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) + 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) @@ -783,12 +799,16 @@ class BCFDB(MyDB): 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) + 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) @@ -807,13 +827,21 @@ class BCFDB(MyDB): 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) + 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) @@ -824,44 +852,44 @@ class BCFDB(MyDB): 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 + 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 + 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 + 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]: + 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') + 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') + 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]: + if "visibility_exception" in components[ifc_guid]: visibility_exception = True - set_list.append('c.visibility_exception = $visibility_exception') + set_list.append("c.visibility_exception = $visibility_exception") else: visibility_exception = False - set_string = ', '.join(set_list) + set_string = ", ".join(set_list) cypher_component = """ MATCH (v:Viewpoint) WHERE v.guid = $viewpoint_id @@ -869,14 +897,16 @@ class BCFDB(MyDB): 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) + 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 @@ -908,26 +938,26 @@ class BCFDB(MyDB): print(cypher_component) raise HTTPException(status_code=400, detail="Item not added.") else: - snapshot_path = '' - bitmap_path = '' + 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 + 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 + 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("could not create file " + snapshot_path + " " + bitmap_path + " ") print(e) raise HTTPException(status_code=400, detail="Item not added.") return viewpoint.guid @@ -950,10 +980,7 @@ class BCFDB(MyDB): 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)) + 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") @@ -976,11 +1003,13 @@ class BCFDB(MyDB): 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)) + 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.") @@ -991,32 +1020,30 @@ class BCFDB(MyDB): 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] - } + 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 + "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'] + 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'] + "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 + 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) @@ -1024,8 +1051,9 @@ class BCFDB(MyDB): 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( + 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) @@ -1036,18 +1064,17 @@ class BCFDB(MyDB): 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)) + 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_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 @@ -1055,8 +1082,9 @@ class BCFDB(MyDB): 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( + 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) @@ -1067,11 +1095,13 @@ class BCFDB(MyDB): 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)) + 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")) @@ -1082,8 +1112,9 @@ class BCFDB(MyDB): 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( + 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) @@ -1094,11 +1125,13 @@ class BCFDB(MyDB): 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)) + 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")) @@ -1109,8 +1142,9 @@ class BCFDB(MyDB): 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( + 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) @@ -1122,12 +1156,14 @@ class BCFDB(MyDB): 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)) + 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) @@ -1146,11 +1182,13 @@ class BCFDB(MyDB): 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)) + 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.") @@ -1160,8 +1198,9 @@ class BCFDB(MyDB): 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( + 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) @@ -1173,36 +1212,36 @@ class BCFDB(MyDB): 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)) + 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 = '' + color = "" coloring = {} occasion = 0 for result in results: component_json = self.node_to_json(result.get("component")) - if component_json['color'] != color: + 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) + color = component_json["color"] + coloring = {"color": color, "components": []} + coloring["components"].append(component_json) coloring_list.append(coloring) - coloring_get = {'coloring': coloring_list} + 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( + 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) @@ -1214,23 +1253,26 @@ class BCFDB(MyDB): 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)) + 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} + 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( + 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) @@ -1241,23 +1283,25 @@ class BCFDB(MyDB): 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)) + 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'] + "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 + "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) @@ -1269,17 +1313,19 @@ class BCFDB(MyDB): 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)) + 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} + visibility["exceptions"] = component_list + visibility_get = {"visibility": visibility} return VisibilityGET(**visibility_get) with self.driver.session() as session: @@ -1297,11 +1343,13 @@ class BCFDB(MyDB): 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 = 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.") @@ -1323,10 +1371,7 @@ class BCFDB(MyDB): 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)) + 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")) @@ -1338,8 +1383,9 @@ class BCFDB(MyDB): 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( + 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 = """ @@ -1352,11 +1398,13 @@ class BCFDB(MyDB): 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) + 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: @@ -1365,8 +1413,9 @@ class BCFDB(MyDB): 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( + 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) @@ -1380,10 +1429,7 @@ class BCFDB(MyDB): 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)) + 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) @@ -1393,19 +1439,22 @@ class BCFDB(MyDB): 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( + 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 + ): document_reference.document_guid = uuid4() - document_url = 'd.url = $url,' + document_url = "d.url = $url," else: - document_url = '' - document_reference.url = '' - cypher = """ + 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 @@ -1415,15 +1464,19 @@ class BCFDB(MyDB): 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) + """ + % 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.") @@ -1434,13 +1487,19 @@ class BCFDB(MyDB): 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]: + 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) + 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 diff --git a/src/opencdeserver/api/app/repository/documents.py b/src/opencdeserver/api/app/repository/documents.py index b48fb886a5..1f5a15440e 100644 --- a/src/opencdeserver/api/app/repository/documents.py +++ b/src/opencdeserver/api/app/repository/documents.py @@ -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', ''), - '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", ""), + "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) diff --git a/src/opencdeserver/api/app/repository/foundation.py b/src/opencdeserver/api/app/repository/foundation.py index 803c70a9d1..2554bfee8d 100644 --- a/src/opencdeserver/api/app/repository/foundation.py +++ b/src/opencdeserver/api/app/repository/foundation.py @@ -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) diff --git a/src/opencdeserver/api/app/security/secrets.py b/src/opencdeserver/api/app/security/secrets.py index 320d70f590..cf7aa1fbe2 100644 --- a/src/opencdeserver/api/app/security/secrets.py +++ b/src/opencdeserver/api/app/security/secrets.py @@ -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 diff --git a/src/opencdeserver/api/app/security/secure.py b/src/opencdeserver/api/app/security/secure.py index 79d98e3c50..cc0027d152 100644 --- a/src/opencdeserver/api/app/security/secure.py +++ b/src/opencdeserver/api/app/security/secure.py @@ -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)