diff --git a/opengeodeweb_back_schemas.json b/opengeodeweb_back_schemas.json index a8a9bd9d..633025ee 100644 --- a/opengeodeweb_back_schemas.json +++ b/opengeodeweb_back_schemas.json @@ -242,17 +242,6 @@ "required": [], "additionalProperties": false }, - "import_extension": { - "$id": "opengeodeweb_back/import_extension", - "route": "/import_extension", - "methods": [ - "POST" - ], - "type": "object", - "properties": {}, - "required": [], - "additionalProperties": false - }, "geographic_coordinate_systems": { "$id": "opengeodeweb_back/geographic_coordinate_systems", "route": "/geographic_coordinate_systems", diff --git a/requirements.txt b/requirements.txt index b855bc40..4504a827 100644 --- a/requirements.txt +++ b/requirements.txt @@ -60,4 +60,3 @@ werkzeug==3.1.2 # flask # flask-cors -opengeodeweb-microservice==1.*,>=1.0.15 diff --git a/src/opengeodeweb_back/routes/blueprint_routes.py b/src/opengeodeweb_back/routes/blueprint_routes.py index fbc14653..7e86fcc2 100644 --- a/src/opengeodeweb_back/routes/blueprint_routes.py +++ b/src/opengeodeweb_back/routes/blueprint_routes.py @@ -543,76 +543,6 @@ def import_project() -> flask.Response: return flask.make_response({"snapshot": snapshot}, 200) -@routes.route( - schemas_dict["import_extension"]["route"], - methods=schemas_dict["import_extension"]["methods"], -) -def import_extension() -> flask.Response: - """Import a .vext extension file and extract its contents.""" - utils_functions.validate_request(flask.request, schemas_dict["import_extension"]) - - if "file" not in flask.request.files: - flask.abort(400, "No .vext file provided under 'file'") - - vext_file = flask.request.files["file"] - assert vext_file.filename is not None - filename = werkzeug.utils.secure_filename(os.path.basename(vext_file.filename)) - - if not filename.lower().endswith(".vext"): - flask.abort(400, "Uploaded file must be a .vext") - - # Create extensions directory in the data folder - extensions_folder = flask.current_app.config["EXTENSIONS_FOLDER_PATH"] - os.makedirs(extensions_folder, exist_ok=True) - - extension_name = ( - filename.rsplit("-", 1)[0] if "-" in filename else filename.replace(".vext", "") - ) - extension_path = os.path.join(extensions_folder, extension_name) - - # Remove existing extension if present - if os.path.exists(extension_path): - shutil.rmtree(extension_path) - - os.makedirs(extension_path, exist_ok=True) - - # Extract the .vext file - vext_file.stream.seek(0) - with zipfile.ZipFile(vext_file.stream) as zip_archive: - zip_archive.extractall(extension_path) - - # Look for the backend executable and frontend JS - backend_executable = None - frontend_file = None - - for file in os.listdir(extension_path): - file_path = os.path.join(extension_path, file) - if os.path.isfile(file_path): - if file.endswith(".es.js"): - frontend_file = file_path - elif not file.endswith(".js") and not file.endswith(".css"): - backend_executable = file_path - os.chmod(backend_executable, 0o755) - - if not frontend_file: - flask.abort(400, "Invalid .vext file: missing frontend JavaScript") - if not backend_executable: - flask.abort(400, "Invalid .vext file: missing backend executable") - - assert frontend_file is not None - with open(frontend_file, "r", encoding="utf-8") as f: - frontend_content = f.read() - - return flask.make_response( - { - "extension_name": extension_name, - "frontend_content": frontend_content, - "backend_path": backend_executable, - }, - 200, - ) - - @routes.route( schemas_dict["geode_object_inheritance"]["route"], methods=schemas_dict["geode_object_inheritance"]["methods"], diff --git a/src/opengeodeweb_back/routes/schemas/__init__.py b/src/opengeodeweb_back/routes/schemas/__init__.py index 606f794f..774f2c76 100644 --- a/src/opengeodeweb_back/routes/schemas/__init__.py +++ b/src/opengeodeweb_back/routes/schemas/__init__.py @@ -9,7 +9,6 @@ from .kill import * from .inspect_file import * from .import_project import * -from .import_extension import * from .geographic_coordinate_systems import * from .geode_objects_and_output_extensions import * from .geode_object_inheritance import * diff --git a/src/opengeodeweb_back/routes/schemas/import_extension.json b/src/opengeodeweb_back/routes/schemas/import_extension.json deleted file mode 100644 index 4d80f553..00000000 --- a/src/opengeodeweb_back/routes/schemas/import_extension.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "route": "/import_extension", - "methods": [ - "POST" - ], - "type": "object", - "properties": {}, - "required": [], - "additionalProperties": false -} diff --git a/src/opengeodeweb_back/routes/schemas/import_extension.py b/src/opengeodeweb_back/routes/schemas/import_extension.py deleted file mode 100644 index 256cb5fa..00000000 --- a/src/opengeodeweb_back/routes/schemas/import_extension.py +++ /dev/null @@ -1,10 +0,0 @@ -from dataclasses_json import DataClassJsonMixin -from dataclasses import dataclass - - -@dataclass -class ImportExtension(DataClassJsonMixin): - def __post_init__(self) -> None: - print(self, flush=True) - - pass diff --git a/tests/test_models_routes.py b/tests/test_models_routes.py index bcd05b63..cb74ce66 100644 --- a/tests/test_models_routes.py +++ b/tests/test_models_routes.py @@ -190,87 +190,3 @@ def test_save_viewable_workflow_from_object(client: FlaskClient) -> None: assert isinstance(data_id, str) and len(data_id) > 0 assert response.get_json()["geode_object_type"] == "PointSet3D" assert response.get_json()["viewable_file"].endswith(".vtp") - - -def test_import_extension_route(client: FlaskClient, tmp_path: Path) -> None: - """Test importing a .vext extension file.""" - route = "/opengeodeweb_back/import_extension" - original_data_folder = client.application.config["DATA_FOLDER_PATH"] - new_data_folder = os.path.join(str(tmp_path), "extension_test_data") - client.application.config["DATA_FOLDER_PATH"] = new_data_folder - client.application.config["EXTENSIONS_FOLDER_PATH"] = os.path.join( - new_data_folder, "extensions" - ) - vext_path = tmp_path / "test-extension-1.0.0.vext" - with zipfile.ZipFile(vext_path, "w", compression=zipfile.ZIP_DEFLATED) as zipf: - zipf.writestr( - "test-extension-extension.es.js", - "export const metadata = { id: 'test-extension', name: 'Test Extension' };", - ) - zipf.writestr("test-extension-back", "#!/bin/bash\necho 'mock backend'") - zipf.writestr("test-extension.css", ".test { color: red; }") - with open(vext_path, "rb") as f: - response = client.post( - route, - data={"file": (f, "test-extension-1.0.0.vext")}, - content_type="multipart/form-data", - ) - assert response.status_code == 200 - json_data = response.get_json() - assert "extension_name" in json_data - assert "frontend_content" in json_data - assert "backend_path" in json_data - assert json_data["extension_name"] == "test-extension" - extensions_folder = os.path.join( - client.application.config["DATA_FOLDER_PATH"], "extensions" - ) - extension_path = os.path.join(extensions_folder, "test-extension") - assert os.path.exists(extension_path) - - # Verify frontend content is returned - frontend_content = json_data["frontend_content"] - assert isinstance(frontend_content, str) - assert len(frontend_content) > 0 - assert "export const metadata" in frontend_content - - backend_exec = json_data["backend_path"] - assert os.path.exists(backend_exec) - assert os.access(backend_exec, os.X_OK) - client.application.config["DATA_FOLDER_PATH"] = original_data_folder - - -def test_import_extension_invalid_file(client: FlaskClient, tmp_path: Path) -> None: - """Test importing an invalid .vext file (missing dist folder).""" - route = "/opengeodeweb_back/import_extension" - original_data_folder = client.application.config["DATA_FOLDER_PATH"] - new_data_folder = os.path.join(str(tmp_path), "extension_invalid_test") - client.application.config["DATA_FOLDER_PATH"] = new_data_folder - client.application.config["EXTENSIONS_FOLDER_PATH"] = os.path.join( - new_data_folder, "extensions" - ) - vext_path = tmp_path / "invalid-extension.vext" - with zipfile.ZipFile(vext_path, "w") as zipf: - zipf.writestr("README.md", "This is invalid") - with open(vext_path, "rb") as f: - response = client.post( - route, - data={"file": (f, "invalid-extension.vext")}, - content_type="multipart/form-data", - ) - assert response.status_code == 400 - client.application.config["DATA_FOLDER_PATH"] = original_data_folder - - -def test_import_extension_wrong_extension(client: FlaskClient, tmp_path: Path) -> None: - """Test uploading a file with wrong extension.""" - route = "/opengeodeweb_back/import_extension" - wrong_file = tmp_path / "not-an-extension.zip" - with open(wrong_file, "wb") as f: - f.write(b"test content") - with open(wrong_file, "rb") as f: - response = client.post( - route, - data={"file": (f, "not-an-extension.zip")}, - content_type="multipart/form-data", - ) - assert response.status_code == 400