From af6aea434e7d4ee3f5fab669a803ef1e8c6d92cd Mon Sep 17 00:00:00 2001 From: MaxNumerique Date: Tue, 24 Feb 2026 14:57:23 +0100 Subject: [PATCH 1/8] feat(CollectionComponents): add collection_components to model_components --- opengeodeweb_back_schemas.json | 6 ++-- .../geode_objects/geode_brep.py | 3 ++ .../geode_objects/geode_model.py | 3 ++ .../geode_objects/geode_section.py | 3 ++ .../routes/models/blueprint_models.py | 32 +++++++++++++++---- .../routes/models/schemas/__init__.py | 2 +- ..._components.json => model_components.json} | 2 +- ...mesh_components.py => model_components.py} | 2 +- tests/test_models_routes.py | 7 ++-- 9 files changed, 46 insertions(+), 14 deletions(-) rename src/opengeodeweb_back/routes/models/schemas/{mesh_components.json => model_components.json} (86%) rename src/opengeodeweb_back/routes/models/schemas/{mesh_components.py => model_components.py} (80%) diff --git a/opengeodeweb_back_schemas.json b/opengeodeweb_back_schemas.json index 2258eed1..9e09d762 100644 --- a/opengeodeweb_back_schemas.json +++ b/opengeodeweb_back_schemas.json @@ -33,9 +33,9 @@ } }, "models": { - "mesh_components": { - "$id": "opengeodeweb_back/models/mesh_components", - "route": "/mesh_components", + "model_components": { + "$id": "opengeodeweb_back/models/model_components", + "route": "/model_components", "methods": [ "POST" ], diff --git a/src/opengeodeweb_back/geode_objects/geode_brep.py b/src/opengeodeweb_back/geode_objects/geode_brep.py index 6637fb9a..5cb1ba92 100644 --- a/src/opengeodeweb_back/geode_objects/geode_brep.py +++ b/src/opengeodeweb_back/geode_objects/geode_brep.py @@ -76,6 +76,9 @@ def save_light_viewable(self, filename_without_extension: str) -> str: def mesh_components(self) -> ComponentRegistry: return self.brep.mesh_components() + def collection_components(self) -> ComponentRegistry: + return self.brep.collection_components() + def inspect(self) -> og_inspector.BRepInspectionResult: return og_inspector.inspect_brep(self.brep) diff --git a/src/opengeodeweb_back/geode_objects/geode_model.py b/src/opengeodeweb_back/geode_objects/geode_model.py index 529fa489..d69aaec3 100644 --- a/src/opengeodeweb_back/geode_objects/geode_model.py +++ b/src/opengeodeweb_back/geode_objects/geode_model.py @@ -23,3 +23,6 @@ def viewer_elements_type(cls) -> ViewerElementsType: @abstractmethod def mesh_components(self) -> ComponentRegistry: ... + + @abstractmethod + def collection_components(self) -> ComponentRegistry: ... diff --git a/src/opengeodeweb_back/geode_objects/geode_section.py b/src/opengeodeweb_back/geode_objects/geode_section.py index af35be7f..17181704 100644 --- a/src/opengeodeweb_back/geode_objects/geode_section.py +++ b/src/opengeodeweb_back/geode_objects/geode_section.py @@ -78,6 +78,9 @@ def save_light_viewable(self, filename_without_extension: str) -> str: def mesh_components(self) -> ComponentRegistry: return self.section.mesh_components() + def collection_components(self) -> ComponentRegistry: + return self.section.collection_components() + def inspect(self) -> og_inspector.SectionInspectionResult: return og_inspector.inspect_section(self.section) diff --git a/src/opengeodeweb_back/routes/models/blueprint_models.py b/src/opengeodeweb_back/routes/models/blueprint_models.py index 287b1860..97d94294 100644 --- a/src/opengeodeweb_back/routes/models/blueprint_models.py +++ b/src/opengeodeweb_back/routes/models/blueprint_models.py @@ -12,14 +12,14 @@ @routes.route( - schemas_dict["mesh_components"]["route"], - methods=schemas_dict["mesh_components"]["methods"], + schemas_dict["model_components"]["route"], + methods=schemas_dict["model_components"]["methods"], ) -def mesh_components() -> flask.Response: +def model_components() -> flask.Response: json_data = utils_functions.validate_request( - flask.request, schemas_dict["mesh_components"] + flask.request, schemas_dict["model_components"] ) - params = schemas.MeshComponents.from_dict(json_data) + params = schemas.ModelComponents.from_dict(json_data) model = geode_functions.load_geode_object(params.id) if not isinstance(model, GeodeModel): flask.abort(400, f"{params.id} is not a GeodeModel") @@ -54,4 +54,24 @@ def mesh_components() -> flask.Response: } mesh_components.append(mesh_component_object) - return flask.make_response({"mesh_components": mesh_components}, 200) + model_collection_components = model.collection_components() + collection_components = [] + for collection_component, ids in model_collection_components.items(): + component_type = collection_component.get() + for id in ids: + geode_id = id.string() + collection_component_object = { + "id": params.id, + "geode_id": geode_id, + "name": geode_id, + "type": component_type, + } + collection_components.append(collection_component_object) + + return flask.make_response( + { + "mesh_components": mesh_components, + "collection_components": collection_components, + }, + 200, + ) diff --git a/src/opengeodeweb_back/routes/models/schemas/__init__.py b/src/opengeodeweb_back/routes/models/schemas/__init__.py index 9455a6fe..4ef41586 100644 --- a/src/opengeodeweb_back/routes/models/schemas/__init__.py +++ b/src/opengeodeweb_back/routes/models/schemas/__init__.py @@ -1 +1 @@ -from .mesh_components import * +from .model_components import * diff --git a/src/opengeodeweb_back/routes/models/schemas/mesh_components.json b/src/opengeodeweb_back/routes/models/schemas/model_components.json similarity index 86% rename from src/opengeodeweb_back/routes/models/schemas/mesh_components.json rename to src/opengeodeweb_back/routes/models/schemas/model_components.json index d8f315aa..b054564d 100644 --- a/src/opengeodeweb_back/routes/models/schemas/mesh_components.json +++ b/src/opengeodeweb_back/routes/models/schemas/model_components.json @@ -1,5 +1,5 @@ { - "route": "/mesh_components", + "route": "/model_components", "methods": [ "POST" ], diff --git a/src/opengeodeweb_back/routes/models/schemas/mesh_components.py b/src/opengeodeweb_back/routes/models/schemas/model_components.py similarity index 80% rename from src/opengeodeweb_back/routes/models/schemas/mesh_components.py rename to src/opengeodeweb_back/routes/models/schemas/model_components.py index 80165275..a471788a 100644 --- a/src/opengeodeweb_back/routes/models/schemas/mesh_components.py +++ b/src/opengeodeweb_back/routes/models/schemas/model_components.py @@ -3,7 +3,7 @@ @dataclass -class MeshComponents(DataClassJsonMixin): +class ModelComponents(DataClassJsonMixin): def __post_init__(self) -> None: print(self, flush=True) diff --git a/tests/test_models_routes.py b/tests/test_models_routes.py index d6fbf7f9..a44fa5bd 100644 --- a/tests/test_models_routes.py +++ b/tests/test_models_routes.py @@ -18,12 +18,12 @@ data_dir = os.path.join(base_dir, "data") -def test_mesh_components(client: FlaskClient) -> None: +def test_model_components(client: FlaskClient) -> None: geode_object_type = "BRep" filename = "cube.og_brep" response = test_save_viewable_file(client, geode_object_type, filename) - route = "/opengeodeweb_back/models/mesh_components" + route = "/opengeodeweb_back/models/model_components" brep_filename = os.path.join(data_dir, "cube.og_brep") response = client.post(route, json={"id": response.get_json()["id"]}) @@ -39,6 +39,9 @@ def test_mesh_components(client: FlaskClient) -> None: assert isinstance(mesh_component["viewer_id"], int) assert isinstance(mesh_component["name"], str) assert isinstance(mesh_component["type"], str) + assert "collection_components" in response.get_json() + collection_components = response.get_json()["collection_components"] + assert isinstance(collection_components, list) def test_export_project_route(client: FlaskClient, tmp_path: Path) -> None: From 02b3e30dfdaf246a1ade58ae6561482ef76b31e0 Mon Sep 17 00:00:00 2001 From: MaxNumerique Date: Tue, 24 Feb 2026 14:59:29 +0100 Subject: [PATCH 2/8] rm geode_id and type --- src/opengeodeweb_back/routes/models/blueprint_models.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/opengeodeweb_back/routes/models/blueprint_models.py b/src/opengeodeweb_back/routes/models/blueprint_models.py index 97d94294..05084a63 100644 --- a/src/opengeodeweb_back/routes/models/blueprint_models.py +++ b/src/opengeodeweb_back/routes/models/blueprint_models.py @@ -62,9 +62,7 @@ def model_components() -> flask.Response: geode_id = id.string() collection_component_object = { "id": params.id, - "geode_id": geode_id, "name": geode_id, - "type": component_type, } collection_components.append(collection_component_object) From 84232a5450f8d6cf9ce2f4965004ea028d51a930 Mon Sep 17 00:00:00 2001 From: MaxNumerique Date: Tue, 24 Feb 2026 15:01:12 +0100 Subject: [PATCH 3/8] refacto --- src/opengeodeweb_back/routes/models/blueprint_models.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/opengeodeweb_back/routes/models/blueprint_models.py b/src/opengeodeweb_back/routes/models/blueprint_models.py index 05084a63..0297e7a2 100644 --- a/src/opengeodeweb_back/routes/models/blueprint_models.py +++ b/src/opengeodeweb_back/routes/models/blueprint_models.py @@ -59,10 +59,9 @@ def model_components() -> flask.Response: for collection_component, ids in model_collection_components.items(): component_type = collection_component.get() for id in ids: - geode_id = id.string() collection_component_object = { "id": params.id, - "name": geode_id, + "name": component_name, } collection_components.append(collection_component_object) From c23351966b93e9cad64b4e4b86882663520a6fbf Mon Sep 17 00:00:00 2001 From: MaxNumerique <144453705+MaxNumerique@users.noreply.github.com> Date: Tue, 24 Feb 2026 14:15:10 +0000 Subject: [PATCH 4/8] Apply prepare changes --- requirements.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 15e1ad30..158e1f59 100644 --- a/requirements.txt +++ b/requirements.txt @@ -60,4 +60,3 @@ werkzeug==3.1.2 # flask # flask-cors -opengeodeweb-microservice==1.*,>=1.0.14 From e3ae6ff06bef8038ff381c4fc65f0af574f94579 Mon Sep 17 00:00:00 2001 From: MaxNumerique Date: Tue, 24 Feb 2026 15:56:01 +0100 Subject: [PATCH 5/8] geode_id as name --- src/opengeodeweb_back/routes/models/blueprint_models.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/opengeodeweb_back/routes/models/blueprint_models.py b/src/opengeodeweb_back/routes/models/blueprint_models.py index 0297e7a2..69478ad7 100644 --- a/src/opengeodeweb_back/routes/models/blueprint_models.py +++ b/src/opengeodeweb_back/routes/models/blueprint_models.py @@ -59,9 +59,10 @@ def model_components() -> flask.Response: for collection_component, ids in model_collection_components.items(): component_type = collection_component.get() for id in ids: + geode_id = id.string() collection_component_object = { - "id": params.id, - "name": component_name, + "id": id, + "name": geode_id, } collection_components.append(collection_component_object) From cf893ddee5dfb35f25c1f4476a684a2d1bb6432e Mon Sep 17 00:00:00 2001 From: MaxNumerique Date: Tue, 24 Feb 2026 16:01:27 +0100 Subject: [PATCH 6/8] params.id & improve test --- src/opengeodeweb_back/routes/models/blueprint_models.py | 2 +- tests/test_models_routes.py | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/opengeodeweb_back/routes/models/blueprint_models.py b/src/opengeodeweb_back/routes/models/blueprint_models.py index 69478ad7..05084a63 100644 --- a/src/opengeodeweb_back/routes/models/blueprint_models.py +++ b/src/opengeodeweb_back/routes/models/blueprint_models.py @@ -61,7 +61,7 @@ def model_components() -> flask.Response: for id in ids: geode_id = id.string() collection_component_object = { - "id": id, + "id": params.id, "name": geode_id, } collection_components.append(collection_component_object) diff --git a/tests/test_models_routes.py b/tests/test_models_routes.py index a44fa5bd..d5a991d2 100644 --- a/tests/test_models_routes.py +++ b/tests/test_models_routes.py @@ -42,6 +42,10 @@ def test_model_components(client: FlaskClient) -> None: assert "collection_components" in response.get_json() collection_components = response.get_json()["collection_components"] assert isinstance(collection_components, list) + for collection_component in collection_components: + assert isinstance(collection_component, object) + assert isinstance(collection_component["id"], str) + assert isinstance(collection_component["name"], str) def test_export_project_route(client: FlaskClient, tmp_path: Path) -> None: From c68ad9e0c59931c855f19741a97553419422f9df Mon Sep 17 00:00:00 2001 From: MaxNumerique Date: Tue, 24 Feb 2026 17:29:10 +0100 Subject: [PATCH 7/8] rm id --- src/opengeodeweb_back/routes/models/blueprint_models.py | 4 ++-- tests/test_models_routes.py | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/opengeodeweb_back/routes/models/blueprint_models.py b/src/opengeodeweb_back/routes/models/blueprint_models.py index 05084a63..8c611726 100644 --- a/src/opengeodeweb_back/routes/models/blueprint_models.py +++ b/src/opengeodeweb_back/routes/models/blueprint_models.py @@ -46,7 +46,6 @@ def model_components() -> flask.Response: viewer_id = uuid_to_flat_index[geode_id] mesh_component_object = { - "id": params.id, "viewer_id": viewer_id, "geode_id": geode_id, "name": component_name, @@ -61,8 +60,9 @@ def model_components() -> flask.Response: for id in ids: geode_id = id.string() collection_component_object = { - "id": params.id, + "geode_id": geode_id, "name": geode_id, + "type": component_type, } collection_components.append(collection_component_object) diff --git a/tests/test_models_routes.py b/tests/test_models_routes.py index d5a991d2..756568ad 100644 --- a/tests/test_models_routes.py +++ b/tests/test_models_routes.py @@ -34,7 +34,6 @@ def test_model_components(client: FlaskClient) -> None: assert len(mesh_components) > 0 for mesh_component in mesh_components: assert isinstance(mesh_component, object) - assert isinstance(mesh_component["id"], str) assert isinstance(mesh_component["geode_id"], str) assert isinstance(mesh_component["viewer_id"], int) assert isinstance(mesh_component["name"], str) @@ -44,7 +43,7 @@ def test_model_components(client: FlaskClient) -> None: assert isinstance(collection_components, list) for collection_component in collection_components: assert isinstance(collection_component, object) - assert isinstance(collection_component["id"], str) + assert isinstance(collection_component["geode_id"], str) assert isinstance(collection_component["name"], str) From 536bbf5a94f3761d30cf973bad30ada53fb36cf3 Mon Sep 17 00:00:00 2001 From: MaxNumerique Date: Wed, 25 Feb 2026 11:06:32 +0100 Subject: [PATCH 8/8] add boundaries, internal and items logic for mesh_components' relations table --- src/opengeodeweb_back/geode_objects/geode_brep.py | 9 +++++++++ src/opengeodeweb_back/geode_objects/geode_model.py | 9 +++++++++ src/opengeodeweb_back/geode_objects/geode_section.py | 9 +++++++++ .../routes/models/blueprint_models.py | 10 +++++++++- tests/test_models_routes.py | 9 +++++++++ 5 files changed, 45 insertions(+), 1 deletion(-) diff --git a/src/opengeodeweb_back/geode_objects/geode_brep.py b/src/opengeodeweb_back/geode_objects/geode_brep.py index 5cb1ba92..5cb32453 100644 --- a/src/opengeodeweb_back/geode_objects/geode_brep.py +++ b/src/opengeodeweb_back/geode_objects/geode_brep.py @@ -79,6 +79,15 @@ def mesh_components(self) -> ComponentRegistry: def collection_components(self) -> ComponentRegistry: return self.brep.collection_components() + def boundaries(self, id: og.uuid) -> list[og.ComponentID]: + return self.brep.boundaries(id) + + def internals(self, id: og.uuid) -> list[og.ComponentID]: + return self.brep.internals(id) + + def items(self, id: og.uuid) -> list[og.ComponentID]: + return self.brep.items(id) + def inspect(self) -> og_inspector.BRepInspectionResult: return og_inspector.inspect_brep(self.brep) diff --git a/src/opengeodeweb_back/geode_objects/geode_model.py b/src/opengeodeweb_back/geode_objects/geode_model.py index d69aaec3..14d867b3 100644 --- a/src/opengeodeweb_back/geode_objects/geode_model.py +++ b/src/opengeodeweb_back/geode_objects/geode_model.py @@ -26,3 +26,12 @@ def mesh_components(self) -> ComponentRegistry: ... @abstractmethod def collection_components(self) -> ComponentRegistry: ... + + @abstractmethod + def boundaries(self, id: og.uuid) -> list[og.ComponentID]: ... + + @abstractmethod + def internals(self, id: og.uuid) -> list[og.ComponentID]: ... + + @abstractmethod + def items(self, id: og.uuid) -> list[og.ComponentID]: ... diff --git a/src/opengeodeweb_back/geode_objects/geode_section.py b/src/opengeodeweb_back/geode_objects/geode_section.py index 17181704..7f2b7dc6 100644 --- a/src/opengeodeweb_back/geode_objects/geode_section.py +++ b/src/opengeodeweb_back/geode_objects/geode_section.py @@ -81,6 +81,15 @@ def mesh_components(self) -> ComponentRegistry: def collection_components(self) -> ComponentRegistry: return self.section.collection_components() + def boundaries(self, id: og.uuid) -> list[og.ComponentID]: + return self.section.boundaries(id) + + def internals(self, id: og.uuid) -> list[og.ComponentID]: + return self.section.internals(id) + + def items(self, id: og.uuid) -> list[og.ComponentID]: + return self.section.items(id) + def inspect(self) -> og_inspector.SectionInspectionResult: return og_inspector.inspect_section(self.section) diff --git a/src/opengeodeweb_back/routes/models/blueprint_models.py b/src/opengeodeweb_back/routes/models/blueprint_models.py index 8c611726..01668f07 100644 --- a/src/opengeodeweb_back/routes/models/blueprint_models.py +++ b/src/opengeodeweb_back/routes/models/blueprint_models.py @@ -44,12 +44,17 @@ def model_components() -> flask.Response: geode_id = id.string() component_name = geode_id viewer_id = uuid_to_flat_index[geode_id] - + boundaries = model.boundaries(id) + boundaries_uuid = [boundary.id().string() for boundary in boundaries] + internals = model.internals(id) + internals_uuid = [internal.id().string() for internal in internals] mesh_component_object = { "viewer_id": viewer_id, "geode_id": geode_id, "name": component_name, "type": component_type, + "boundaries": boundaries_uuid, + "internals": internals_uuid, } mesh_components.append(mesh_component_object) @@ -59,10 +64,13 @@ def model_components() -> flask.Response: component_type = collection_component.get() for id in ids: geode_id = id.string() + items = model.items(id) + items_uuid = [item.id().string() for item in items] collection_component_object = { "geode_id": geode_id, "name": geode_id, "type": component_type, + "items": items_uuid, } collection_components.append(collection_component_object) diff --git a/tests/test_models_routes.py b/tests/test_models_routes.py index 756568ad..72bf0fa7 100644 --- a/tests/test_models_routes.py +++ b/tests/test_models_routes.py @@ -38,6 +38,12 @@ def test_model_components(client: FlaskClient) -> None: assert isinstance(mesh_component["viewer_id"], int) assert isinstance(mesh_component["name"], str) assert isinstance(mesh_component["type"], str) + assert isinstance(mesh_component["boundaries"], list) + for boundary_uuid in mesh_component["boundaries"]: + assert isinstance(boundary_uuid, str) + assert isinstance(mesh_component["internals"], list) + for internal_uuid in mesh_component["internals"]: + assert isinstance(internal_uuid, str) assert "collection_components" in response.get_json() collection_components = response.get_json()["collection_components"] assert isinstance(collection_components, list) @@ -45,6 +51,9 @@ def test_model_components(client: FlaskClient) -> None: assert isinstance(collection_component, object) assert isinstance(collection_component["geode_id"], str) assert isinstance(collection_component["name"], str) + assert isinstance(collection_component["items"], list) + for item_uuid in collection_component["items"]: + assert isinstance(item_uuid, str) def test_export_project_route(client: FlaskClient, tmp_path: Path) -> None: