From c53d02827ef534654bc71851c99bb49a0972c61c Mon Sep 17 00:00:00 2001 From: JulienChampagnol Date: Thu, 15 Jan 2026 09:20:18 +0100 Subject: [PATCH 1/2] fix(Models): single route for models mesh_components BREAKING CHANGE: deletes vtm_component_indices route --- opengeodeweb_back_schemas.json | 18 ---- .../routes/models/blueprint_models.py | 54 ++++++------ .../routes/models/schemas/__init__.py | 1 - .../models/schemas/vtm_component_indices.json | 17 ---- .../models/schemas/vtm_component_indices.py | 10 --- tests/test_models_routes.py | 85 +++++-------------- tests/test_routes.py | 11 +-- 7 files changed, 55 insertions(+), 141 deletions(-) delete mode 100644 src/opengeodeweb_back/routes/models/schemas/vtm_component_indices.json delete mode 100644 src/opengeodeweb_back/routes/models/schemas/vtm_component_indices.py diff --git a/opengeodeweb_back_schemas.json b/opengeodeweb_back_schemas.json index 50408514..ef829502 100644 --- a/opengeodeweb_back_schemas.json +++ b/opengeodeweb_back_schemas.json @@ -33,24 +33,6 @@ } }, "models": { - "vtm_component_indices": { - "$id": "opengeodeweb_back/models/vtm_component_indices", - "route": "/vtm_component_indices", - "methods": [ - "POST" - ], - "type": "object", - "properties": { - "id": { - "type": "string", - "minLength": 1 - } - }, - "required": [ - "id" - ], - "additionalProperties": false - }, "mesh_components": { "$id": "opengeodeweb_back/models/mesh_components", "route": "/mesh_components", diff --git a/src/opengeodeweb_back/routes/models/blueprint_models.py b/src/opengeodeweb_back/routes/models/blueprint_models.py index 5d18349b..cd982771 100644 --- a/src/opengeodeweb_back/routes/models/blueprint_models.py +++ b/src/opengeodeweb_back/routes/models/blueprint_models.py @@ -10,16 +10,20 @@ routes = flask.Blueprint("models", __name__, url_prefix="/models") schemas_dict = get_schemas_dict(os.path.join(os.path.dirname(__file__), "schemas")) - @routes.route( - schemas_dict["vtm_component_indices"]["route"], - methods=schemas_dict["vtm_component_indices"]["methods"], + schemas_dict["mesh_components"]["route"], + methods=schemas_dict["mesh_components"]["methods"], ) -def uuid_to_flat_index() -> flask.Response: +def mesh_components() -> flask.Response: json_data = utils_functions.validate_request( - flask.request, schemas_dict["vtm_component_indices"] + flask.request, schemas_dict["mesh_components"] ) - params = schemas.VtmComponentIndices.from_dict(json_data) + params = schemas.MeshComponents.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") + + vtm_file_path = geode_functions.data_file_path(params.id, "viewable.vtm") tree = ET.parse(vtm_file_path) root = tree.find("vtkMultiBlockDataSet") @@ -32,24 +36,22 @@ def uuid_to_flat_index() -> flask.Response: if "uuid" in elem.attrib and elem.tag == "DataSet": uuid_to_flat_index[elem.attrib["uuid"]] = current_index current_index += 1 - return flask.make_response({"uuid_to_flat_index": uuid_to_flat_index}, 200) - + model_mesh_components = model.mesh_components() + mesh_components = [] + for mesh_component, ids in model_mesh_components.items(): + component_type = mesh_component.get() + for id in ids: + geode_id = id.string() + component_name = geode_id + 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, + "type": component_type + } + mesh_components.append(mesh_component_object) -@routes.route( - schemas_dict["mesh_components"]["route"], - methods=schemas_dict["mesh_components"]["methods"], -) -def extract_uuids_endpoint() -> flask.Response: - json_data = utils_functions.validate_request( - flask.request, schemas_dict["mesh_components"] - ) - params = schemas.MeshComponents.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") - mesh_components = model.mesh_components() - uuid_dict = {} - for mesh_component, ids in mesh_components.items(): - component_name = mesh_component.get() - uuid_dict[component_name] = [id.string() for id in ids] - return flask.make_response({"uuid_dict": uuid_dict}, 200) + return flask.make_response({"mesh_components": mesh_components}, 200) diff --git a/src/opengeodeweb_back/routes/models/schemas/__init__.py b/src/opengeodeweb_back/routes/models/schemas/__init__.py index ae37331e..9455a6fe 100644 --- a/src/opengeodeweb_back/routes/models/schemas/__init__.py +++ b/src/opengeodeweb_back/routes/models/schemas/__init__.py @@ -1,2 +1 @@ -from .vtm_component_indices import * from .mesh_components import * diff --git a/src/opengeodeweb_back/routes/models/schemas/vtm_component_indices.json b/src/opengeodeweb_back/routes/models/schemas/vtm_component_indices.json deleted file mode 100644 index 0618e60a..00000000 --- a/src/opengeodeweb_back/routes/models/schemas/vtm_component_indices.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "route": "/vtm_component_indices", - "methods": [ - "POST" - ], - "type": "object", - "properties": { - "id": { - "type": "string", - "minLength": 1 - } - }, - "required": [ - "id" - ], - "additionalProperties": false -} \ No newline at end of file diff --git a/src/opengeodeweb_back/routes/models/schemas/vtm_component_indices.py b/src/opengeodeweb_back/routes/models/schemas/vtm_component_indices.py deleted file mode 100644 index 25ece214..00000000 --- a/src/opengeodeweb_back/routes/models/schemas/vtm_component_indices.py +++ /dev/null @@ -1,10 +0,0 @@ -from dataclasses_json import DataClassJsonMixin -from dataclasses import dataclass - - -@dataclass -class VtmComponentIndices(DataClassJsonMixin): - def __post_init__(self) -> None: - print(self, flush=True) - - id: str diff --git a/tests/test_models_routes.py b/tests/test_models_routes.py index 0b272202..b7bd2598 100644 --- a/tests/test_models_routes.py +++ b/tests/test_models_routes.py @@ -11,51 +11,36 @@ from opengeodeweb_back import geode_functions from opengeodeweb_back.geode_objects.geode_brep import GeodeBRep -base_dir = os.path.abspath(os.path.dirname(__file__)) -data_dir = os.path.join(base_dir, "data") - -def test_model_mesh_components(client: FlaskClient, test_id: str) -> None: - route = "/opengeodeweb_back/models/vtm_component_indices" - - with client.application.app_context(): - data_path = geode_functions.data_file_path(test_id, "viewable.vtm") - os.makedirs(os.path.dirname(data_path), exist_ok=True) - shutil.copy(os.path.join(data_dir, "cube.vtm"), data_path) - - response = client.post(route, json={"id": test_id}) - assert response.status_code == 200 +from .test_routes import test_save_viewable_file - uuid_dict = response.get_json()["uuid_to_flat_index"] - assert isinstance(uuid_dict, dict) +base_dir = os.path.abspath(os.path.dirname(__file__)) +data_dir = os.path.join(base_dir, "data") - indices = list(uuid_dict.values()) - indices.sort() - assert all(indices[i] > indices[i - 1] for i in range(1, len(indices))) - for uuid in uuid_dict.keys(): - assert isinstance(uuid, str) +def test_mesh_components(client: FlaskClient) -> None: + geode_object_type = "BRep" + filename = "cube.og_brep" + response = test_save_viewable_file(client, geode_object_type, filename) -def test_extract_brep_uuids(client: FlaskClient, test_id: str) -> None: route = "/opengeodeweb_back/models/mesh_components" brep_filename = os.path.join(data_dir, "cube.og_brep") - with client.application.app_context(): - data = Data.create( - geode_object=GeodeBRep.geode_object_type(), - viewer_object=GeodeBRep.viewer_type(), - input_file=brep_filename, - ) - data.native_file = brep_filename - session = get_session() - if session: - session.commit() - response = client.post(route, json={"id": data.id}) - assert response.status_code == 200 - assert "uuid_dict" in response.get_json() - uuid_dict = response.get_json()["uuid_dict"] - assert isinstance(uuid_dict, dict) + response = client.post(route, json={"id": response.get_json()["id"]}) + assert response.status_code == 200 + assert "mesh_components" in response.get_json() + mesh_components = response.get_json()["mesh_components"] + assert isinstance(mesh_components, list) + 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) + assert isinstance(mesh_component["type"], str) + def test_export_project_route(client: FlaskClient, tmp_path: Path) -> None: @@ -177,34 +162,6 @@ def test_import_project_route(client: FlaskClient, tmp_path: Path) -> None: client.application.config["DATA_FOLDER_PATH"] = original_data_folder - -def test_save_viewable_workflow_from_file(client: FlaskClient) -> None: - file = os.path.join(data_dir, "cube.og_brep") - upload_resp = client.put( - "/opengeodeweb_back/upload_file", - data={"file": FileStorage(open(file, "rb"))}, - ) - assert upload_resp.status_code == 201 - - route = "/opengeodeweb_back/save_viewable_file" - payload = {"geode_object_type": "BRep", "filename": "cube.og_brep"} - - response = client.post(route, json=payload) - assert response.status_code == 200 - - data_id = response.get_json()["id"] - assert isinstance(data_id, str) and len(data_id) > 0 - assert response.get_json()["viewable_file"].endswith(".vtm") - - comp_resp = client.post( - "/opengeodeweb_back/models/vtm_component_indices", json={"id": data_id} - ) - assert comp_resp.status_code == 200 - - refreshed = Data.get(data_id) - assert refreshed is not None - - def test_save_viewable_workflow_from_object(client: FlaskClient) -> None: route = "/opengeodeweb_back/create/point" point_data = { diff --git a/tests/test_routes.py b/tests/test_routes.py index 69c42c9f..3be18a7a 100644 --- a/tests/test_routes.py +++ b/tests/test_routes.py @@ -4,6 +4,7 @@ # Third party imports from werkzeug.datastructures import FileStorage from flask.testing import FlaskClient +from werkzeug.test import TestResponse # Local application imports from opengeodeweb_microservice.database.data import Data @@ -160,14 +161,14 @@ def get_full_data() -> test_utils.JsonData: test_utils.test_route_wrong_params(client, route, get_full_data) -def test_save_viewable_file(client: FlaskClient) -> None: - test_upload_file(client, filename="corbi.og_brep") +def test_save_viewable_file(client: FlaskClient, geode_object_type: str = "BRep", filename: str = "corbi.og_brep") -> TestResponse: + test_upload_file(client, filename) route = f"/opengeodeweb_back/save_viewable_file" def get_full_data() -> test_utils.JsonData: return { - "geode_object_type": "BRep", - "filename": "corbi.og_brep", + "geode_object_type": geode_object_type, + "filename": filename, } # Normal test with filename 'corbi.og_brep' @@ -187,7 +188,7 @@ def get_full_data() -> test_utils.JsonData: # Test all params test_utils.test_route_wrong_params(client, route, get_full_data) - + return response def test_texture_coordinates(client: FlaskClient, test_id: str) -> None: with client.application.app_context(): From 5eeced4dbd1112852193e23e714c3518076b31ba Mon Sep 17 00:00:00 2001 From: JulienChampagnol <91873154+JulienChampagnol@users.noreply.github.com> Date: Thu, 15 Jan 2026 08:21:40 +0000 Subject: [PATCH 2/2] Apply prepare changes --- requirements.txt | 1 - src/opengeodeweb_back/routes/models/blueprint_models.py | 6 +++--- tests/test_models_routes.py | 3 +-- tests/test_routes.py | 7 ++++++- 4 files changed, 10 insertions(+), 7 deletions(-) diff --git a/requirements.txt b/requirements.txt index 5697c0a5..08d64bdf 100644 --- a/requirements.txt +++ b/requirements.txt @@ -60,4 +60,3 @@ werkzeug==3.1.2 # flask # flask-cors -opengeodeweb-microservice==1.*,>=1.0.12 diff --git a/src/opengeodeweb_back/routes/models/blueprint_models.py b/src/opengeodeweb_back/routes/models/blueprint_models.py index cd982771..287b1860 100644 --- a/src/opengeodeweb_back/routes/models/blueprint_models.py +++ b/src/opengeodeweb_back/routes/models/blueprint_models.py @@ -10,6 +10,7 @@ routes = flask.Blueprint("models", __name__, url_prefix="/models") schemas_dict = get_schemas_dict(os.path.join(os.path.dirname(__file__), "schemas")) + @routes.route( schemas_dict["mesh_components"]["route"], methods=schemas_dict["mesh_components"]["methods"], @@ -23,7 +24,6 @@ def mesh_components() -> flask.Response: if not isinstance(model, GeodeModel): flask.abort(400, f"{params.id} is not a GeodeModel") - vtm_file_path = geode_functions.data_file_path(params.id, "viewable.vtm") tree = ET.parse(vtm_file_path) root = tree.find("vtkMultiBlockDataSet") @@ -44,13 +44,13 @@ def mesh_components() -> flask.Response: geode_id = id.string() component_name = geode_id 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, - "type": component_type + "type": component_type, } mesh_components.append(mesh_component_object) diff --git a/tests/test_models_routes.py b/tests/test_models_routes.py index b7bd2598..cc555627 100644 --- a/tests/test_models_routes.py +++ b/tests/test_models_routes.py @@ -26,7 +26,6 @@ def test_mesh_components(client: FlaskClient) -> None: route = "/opengeodeweb_back/models/mesh_components" brep_filename = os.path.join(data_dir, "cube.og_brep") - response = client.post(route, json={"id": response.get_json()["id"]}) assert response.status_code == 200 assert "mesh_components" in response.get_json() @@ -42,7 +41,6 @@ def test_mesh_components(client: FlaskClient) -> None: assert isinstance(mesh_component["type"], str) - def test_export_project_route(client: FlaskClient, tmp_path: Path) -> None: route = "/opengeodeweb_back/export_project" snapshot = { @@ -162,6 +160,7 @@ def test_import_project_route(client: FlaskClient, tmp_path: Path) -> None: client.application.config["DATA_FOLDER_PATH"] = original_data_folder + def test_save_viewable_workflow_from_object(client: FlaskClient) -> None: route = "/opengeodeweb_back/create/point" point_data = { diff --git a/tests/test_routes.py b/tests/test_routes.py index 3be18a7a..58aa3321 100644 --- a/tests/test_routes.py +++ b/tests/test_routes.py @@ -161,7 +161,11 @@ def get_full_data() -> test_utils.JsonData: test_utils.test_route_wrong_params(client, route, get_full_data) -def test_save_viewable_file(client: FlaskClient, geode_object_type: str = "BRep", filename: str = "corbi.og_brep") -> TestResponse: +def test_save_viewable_file( + client: FlaskClient, + geode_object_type: str = "BRep", + filename: str = "corbi.og_brep", +) -> TestResponse: test_upload_file(client, filename) route = f"/opengeodeweb_back/save_viewable_file" @@ -190,6 +194,7 @@ def get_full_data() -> test_utils.JsonData: test_utils.test_route_wrong_params(client, route, get_full_data) return response + def test_texture_coordinates(client: FlaskClient, test_id: str) -> None: with client.application.app_context(): file = os.path.join(data_dir, "hat.vtp")