From 307c5cbc94fde7d4a64b592681cf6cba774e01f5 Mon Sep 17 00:00:00 2001 From: JulienChampagnol Date: Mon, 29 Jun 2026 11:24:29 +0200 Subject: [PATCH 01/22] fix(Config): refactor project/data_folder_path --- src/opengeodeweb_back/app.py | 21 ++++++++---------- src/opengeodeweb_back/app_config.py | 18 +++++++-------- src/opengeodeweb_back/geode_functions.py | 2 +- .../routes/blueprint_routes.py | 22 ++++++++++++------- tests/conftest.py | 2 +- tests/test_utils_functions.py | 12 +++++----- 6 files changed, 40 insertions(+), 37 deletions(-) diff --git a/src/opengeodeweb_back/app.py b/src/opengeodeweb_back/app.py index 7422ad4b..08773700 100644 --- a/src/opengeodeweb_back/app.py +++ b/src/opengeodeweb_back/app.py @@ -102,14 +102,14 @@ def run_server(app: Flask) -> None: parser.add_argument( "--host", type=str, - default=app.config.get("DEFAULT_HOST"), + default=app.config.get("HOST"), help="Host to run on", ) parser.add_argument( "-p", "--port", type=int, - default=app.config.get("DEFAULT_PORT"), + default=app.config.get("PORT"), help="Port to listen on", ) parser.add_argument( @@ -120,17 +120,17 @@ def run_server(app: Flask) -> None: action="store_true", ) parser.add_argument( - "-dfp", - "--data_folder_path", + "-pfp", + "--project_folder_path", type=str, - default=app.config.get("DEFAULT_DATA_FOLDER_PATH"), - help="Path to the folder where data is stored", + default=app.config.get("PROJECT_FOLDER_PATH"), + help="Path to the folder where the project is stored", ) parser.add_argument( "-ufp", "--upload_folder_path", type=str, - default=app.config.get("UPLOAD_FOLDER"), + default=app.config.get("UPLOAD_FOLDER_PATH"), help="Path to the folder where uploads are stored", ) parser.add_argument( @@ -147,11 +147,8 @@ def run_server(app: Flask) -> None: help="Number of minutes before the server times out", ) args, _ = parser.parse_known_args() - app.config.update(DATA_FOLDER_PATH=args.data_folder_path) - app.config.update( - EXTENSIONS_FOLDER_PATH=os.path.join(str(args.data_folder_path), "extensions") - ) - app.config.update(UPLOAD_FOLDER=args.upload_folder_path) + app.config.update(PROJECT_FOLDER_PATH=args.project_folder_path) + app.config.update(UPLOAD_FOLDER_PATH=args.upload_folder_path) app.config.update(MINUTES_BEFORE_TIMEOUT=args.timeout) flask_cors.CORS(app, origins=args.allowed_origins) print(f"{args=}", flush=True) diff --git a/src/opengeodeweb_back/app_config.py b/src/opengeodeweb_back/app_config.py index 2b17c4dc..395e122d 100644 --- a/src/opengeodeweb_back/app_config.py +++ b/src/opengeodeweb_back/app_config.py @@ -8,10 +8,13 @@ class Config(object): FLASK_DEBUG = os.environ.get("FLASK_DEBUG", default=False) - DEFAULT_HOST = "localhost" - DEFAULT_PORT = "5000" + HOST = "localhost" + PORT = "5000" CORS_HEADERS = "Content-Type" - UPLOAD_FOLDER = "./uploads" + PROJECT_FOLDER_PATH = "/project" + DATA_FOLDER_PATH = os.path.join(PROJECT_FOLDER_PATH, "data") + EXTENSIONS_FOLDER_PATH = os.path.join(PROJECT_FOLDER_PATH, "exensions") + UPLOAD_FOLDER_PATH = os.path.join(PROJECT_FOLDER_PATH, "uploads") REQUEST_COUNTER = 0 LAST_REQUEST_TIME = time.time() LAST_PING_TIME = time.time() @@ -23,15 +26,12 @@ class ProdConfig(Config): ORIGINS = "" MINUTES_BEFORE_TIMEOUT = "1" SECONDS_BETWEEN_SHUTDOWNS = "10" - DATA_FOLDER_PATH = "/data" - EXTENSIONS_FOLDER_PATH = os.path.join(DATA_FOLDER_PATH, "extensions") - + PROJECT_FOLDER_PATH = "/project" +t class DevConfig(Config): SSL = None ORIGINS = "*" MINUTES_BEFORE_TIMEOUT = "1" SECONDS_BETWEEN_SHUTDOWNS = "10" - BASE_DIR = os.path.dirname(os.path.abspath(__file__)) - DATA_FOLDER_PATH = os.path.join(BASE_DIR, "data") - EXTENSIONS_FOLDER_PATH = os.path.join(DATA_FOLDER_PATH, "extensions") + PROJECT_FOLDER_PATH = os.path.dirname(os.path.abspath(__file__)) diff --git a/src/opengeodeweb_back/geode_functions.py b/src/opengeodeweb_back/geode_functions.py index 791ebbaa..28e96094 100644 --- a/src/opengeodeweb_back/geode_functions.py +++ b/src/opengeodeweb_back/geode_functions.py @@ -46,7 +46,7 @@ def get_data_info(data_id: str) -> Data: def upload_file_path(filename: str) -> str: - upload_folder = flask.current_app.config["UPLOAD_FOLDER"] + upload_folder = flask.current_app.config["UPLOAD_FOLDER_PATH"] secure_filename = werkzeug.utils.secure_filename(filename) return os.path.abspath(os.path.join(upload_folder, secure_filename)) diff --git a/src/opengeodeweb_back/routes/blueprint_routes.py b/src/opengeodeweb_back/routes/blueprint_routes.py index d97df6e5..f915abba 100644 --- a/src/opengeodeweb_back/routes/blueprint_routes.py +++ b/src/opengeodeweb_back/routes/blueprint_routes.py @@ -66,20 +66,20 @@ def allowed_files() -> flask.Response: methods=schemas_dict["upload_file"]["methods"], ) def upload_file() -> flask.Response: - UPLOAD_FOLDER = flask.current_app.config["UPLOAD_FOLDER"] - print(f"{UPLOAD_FOLDER=}", flush=True) - if not os.path.exists(UPLOAD_FOLDER): - os.makedirs(UPLOAD_FOLDER, exist_ok=True) + UPLOAD_FOLDER_PATH = flask.current_app.config["UPLOAD_FOLDER_PATH"] + print(f"{UPLOAD_FOLDER_PATH=}", flush=True) + if not os.path.exists(UPLOAD_FOLDER_PATH): + os.makedirs(UPLOAD_FOLDER_PATH, exist_ok=True) file = flask.request.files["file"] if file.filename is None: flask.abort(400, "Filename is required") filename = werkzeug.utils.secure_filename(os.path.basename(file.filename)) print(f"{filename=}", flush=True) - file_path = os.path.join(UPLOAD_FOLDER, filename) + file_path = os.path.join(UPLOAD_FOLDER_PATH, filename) file.save(file_path) if filename.lower().endswith(".csv.json"): - shutil.copyfile(file_path, os.path.join(UPLOAD_FOLDER, filename[:-9] + ".json")) + shutil.copyfile(file_path, os.path.join(UPLOAD_FOLDER_PATH, filename[:-9] + ".json")) return flask.make_response({"message": "File uploaded"}, 201) @@ -585,11 +585,17 @@ def import_project() -> flask.Response: try: if os.path.exists(data_folder_path): - shutil.rmtree(data_folder_path) - os.makedirs(data_folder_path, exist_ok=True) + for item in os.scandir(data_folder_path): + if item.is_dir(follow_symlinks=False): + shutil.rmtree(item.path) + else: + os.remove(item.path) + else: + os.makedirs(data_folder_path, exist_ok=True) except PermissionError: flask.abort(423, "Project files are locked; cannot overwrite") + zip_file.stream.seek(0) with zipfile.ZipFile(zip_file.stream) as zip_archive: project_folder = os.path.abspath(data_folder_path) diff --git a/tests/conftest.py b/tests/conftest.py index be69c56c..2220afb2 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -31,7 +31,7 @@ def configure_test_environment() -> Generator[None, None, None]: app.config["TESTING"] = True app.config["SERVER_NAME"] = "TEST" app.config["DATA_FOLDER_PATH"] = "./data/" - app.config["UPLOAD_FOLDER"] = "./tests/data/" + app.config["UPLOAD_FOLDER_PATH"] = "./tests/data/" db_path = os.path.join(base_path, "data", "project.db") app.config["SQLALCHEMY_DATABASE_URI"] = f"sqlite:///{db_path}" diff --git a/tests/test_utils_functions.py b/tests/test_utils_functions.py index 2d662f57..2e526277 100644 --- a/tests/test_utils_functions.py +++ b/tests/test_utils_functions.py @@ -232,7 +232,7 @@ def test_generate_native_viewable_and_light_viewable_from_file_with_multi_dots( def test_send_file_multiple_returns_zip(client: FlaskClient, tmp_path: Path) -> None: app = client.application with app.app_context(): - app.config["UPLOAD_FOLDER"] = str(tmp_path) + app.config["UPLOAD_FOLDER_PATH"] = str(tmp_path) file_paths = [] for i, content in [(1, b"hello 1"), (2, b"hello 2")]: file_path = tmp_path / f"tmp_send_file_{i}.txt" @@ -240,13 +240,13 @@ def test_send_file_multiple_returns_zip(client: FlaskClient, tmp_path: Path) -> file_paths.append(str(file_path)) with app.test_request_context(): response = utils_functions.send_file( - app.config["UPLOAD_FOLDER"], file_paths, "bundle" + app.config["UPLOAD_FOLDER_PATH"], file_paths, "bundle" ) assert response.status_code == 200 assert response.mimetype == "application/zip" new_file_name = response.headers.get("new-file-name") assert new_file_name == "bundle.zip" - zip_path = os.path.join(app.config["UPLOAD_FOLDER"], new_file_name) + zip_path = os.path.join(app.config["UPLOAD_FOLDER_PATH"], new_file_name) with zipfile.ZipFile(zip_path, "r") as zip_file: zip_entries = zip_file.namelist() assert "tmp_send_file_1.txt" in zip_entries @@ -259,18 +259,18 @@ def test_send_file_single_returns_octet_binary( ) -> None: app = client.application with app.app_context(): - app.config["UPLOAD_FOLDER"] = str(tmp_path) + app.config["UPLOAD_FOLDER_PATH"] = str(tmp_path) file_path = tmp_path / "tmp_send_file_1.txt" file_path.write_bytes(b"hello 1") with app.test_request_context(): response = utils_functions.send_file( - app.config["UPLOAD_FOLDER"], [str(file_path)], "tmp_send_file_1.txt" + app.config["UPLOAD_FOLDER_PATH"], [str(file_path)], "tmp_send_file_1.txt" ) assert response.status_code == 200 assert response.mimetype == "application/octet-binary" new_file_name = response.headers.get("new-file-name") assert new_file_name == "tmp_send_file_1.txt" - zip_path = os.path.join(app.config["UPLOAD_FOLDER"], new_file_name) + zip_path = os.path.join(app.config["UPLOAD_FOLDER_PATH"], new_file_name) with open(zip_path, "rb") as f: file_bytes = f.read() assert file_bytes == b"hello 1" From 14086b4ca36d6f12cf3a150a90b3f11166d37a56 Mon Sep 17 00:00:00 2001 From: JulienChampagnol Date: Mon, 29 Jun 2026 12:03:33 +0200 Subject: [PATCH 02/22] test --- src/opengeodeweb_back/app_config.py | 1 - tests/conftest.py | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/opengeodeweb_back/app_config.py b/src/opengeodeweb_back/app_config.py index 395e122d..ddec3f36 100644 --- a/src/opengeodeweb_back/app_config.py +++ b/src/opengeodeweb_back/app_config.py @@ -28,7 +28,6 @@ class ProdConfig(Config): SECONDS_BETWEEN_SHUTDOWNS = "10" PROJECT_FOLDER_PATH = "/project" -t class DevConfig(Config): SSL = None ORIGINS = "*" diff --git a/tests/conftest.py b/tests/conftest.py index 2220afb2..4d5ca51b 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -30,7 +30,7 @@ def configure_test_environment() -> Generator[None, None, None]: app.config["TESTING"] = True app.config["SERVER_NAME"] = "TEST" - app.config["DATA_FOLDER_PATH"] = "./data/" + app.config["PROJECT_FOLDER_PATH"] = "./" app.config["UPLOAD_FOLDER_PATH"] = "./tests/data/" db_path = os.path.join(base_path, "data", "project.db") From 3b271a038abaf8063790c1218ea1ce7c3b288ead Mon Sep 17 00:00:00 2001 From: JulienChampagnol <91873154+JulienChampagnol@users.noreply.github.com> Date: Mon, 29 Jun 2026 11:31:04 +0000 Subject: [PATCH 03/22] Apply prepare changes --- requirements.txt | 1 - src/opengeodeweb_back/app_config.py | 7 +++++-- src/opengeodeweb_back/routes/blueprint_routes.py | 5 +++-- tests/test_utils_functions.py | 4 +++- 4 files changed, 11 insertions(+), 6 deletions(-) diff --git a/requirements.txt b/requirements.txt index 76111aa7..ff9ae20e 100644 --- a/requirements.txt +++ b/requirements.txt @@ -60,4 +60,3 @@ werkzeug==3.1.8 # flask # flask-cors -opengeodeweb-microservice==1.*,>=1.1.3 diff --git a/src/opengeodeweb_back/app_config.py b/src/opengeodeweb_back/app_config.py index 395e122d..e8f172cf 100644 --- a/src/opengeodeweb_back/app_config.py +++ b/src/opengeodeweb_back/app_config.py @@ -12,9 +12,9 @@ class Config(object): PORT = "5000" CORS_HEADERS = "Content-Type" PROJECT_FOLDER_PATH = "/project" - DATA_FOLDER_PATH = os.path.join(PROJECT_FOLDER_PATH, "data") + DATA_FOLDER_PATH = os.path.join(PROJECT_FOLDER_PATH, "data") EXTENSIONS_FOLDER_PATH = os.path.join(PROJECT_FOLDER_PATH, "exensions") - UPLOAD_FOLDER_PATH = os.path.join(PROJECT_FOLDER_PATH, "uploads") + UPLOAD_FOLDER_PATH = os.path.join(PROJECT_FOLDER_PATH, "uploads") REQUEST_COUNTER = 0 LAST_REQUEST_TIME = time.time() LAST_PING_TIME = time.time() @@ -28,7 +28,10 @@ class ProdConfig(Config): SECONDS_BETWEEN_SHUTDOWNS = "10" PROJECT_FOLDER_PATH = "/project" + t + + class DevConfig(Config): SSL = None ORIGINS = "*" diff --git a/src/opengeodeweb_back/routes/blueprint_routes.py b/src/opengeodeweb_back/routes/blueprint_routes.py index f915abba..f84a419a 100644 --- a/src/opengeodeweb_back/routes/blueprint_routes.py +++ b/src/opengeodeweb_back/routes/blueprint_routes.py @@ -79,7 +79,9 @@ def upload_file() -> flask.Response: file_path = os.path.join(UPLOAD_FOLDER_PATH, filename) file.save(file_path) if filename.lower().endswith(".csv.json"): - shutil.copyfile(file_path, os.path.join(UPLOAD_FOLDER_PATH, filename[:-9] + ".json")) + shutil.copyfile( + file_path, os.path.join(UPLOAD_FOLDER_PATH, filename[:-9] + ".json") + ) return flask.make_response({"message": "File uploaded"}, 201) @@ -595,7 +597,6 @@ def import_project() -> flask.Response: except PermissionError: flask.abort(423, "Project files are locked; cannot overwrite") - zip_file.stream.seek(0) with zipfile.ZipFile(zip_file.stream) as zip_archive: project_folder = os.path.abspath(data_folder_path) diff --git a/tests/test_utils_functions.py b/tests/test_utils_functions.py index 2e526277..c041c4a8 100644 --- a/tests/test_utils_functions.py +++ b/tests/test_utils_functions.py @@ -264,7 +264,9 @@ def test_send_file_single_returns_octet_binary( file_path.write_bytes(b"hello 1") with app.test_request_context(): response = utils_functions.send_file( - app.config["UPLOAD_FOLDER_PATH"], [str(file_path)], "tmp_send_file_1.txt" + app.config["UPLOAD_FOLDER_PATH"], + [str(file_path)], + "tmp_send_file_1.txt", ) assert response.status_code == 200 assert response.mimetype == "application/octet-binary" From bc37237614692b229b7a4b91957b175d84e9bf70 Mon Sep 17 00:00:00 2001 From: JulienChampagnol Date: Mon, 29 Jun 2026 12:18:59 +0200 Subject: [PATCH 04/22] test From 525fc8e0da8eb9fa8851a64064399882756301e5 Mon Sep 17 00:00:00 2001 From: JulienChampagnol Date: Mon, 29 Jun 2026 13:06:45 +0200 Subject: [PATCH 05/22] test --- src/opengeodeweb_back/app_config.py | 1 - src/opengeodeweb_back/geode_objects/geode_brep.py | 2 ++ tests/conftest.py | 4 ++-- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/opengeodeweb_back/app_config.py b/src/opengeodeweb_back/app_config.py index cf98f689..a9299513 100644 --- a/src/opengeodeweb_back/app_config.py +++ b/src/opengeodeweb_back/app_config.py @@ -26,7 +26,6 @@ class ProdConfig(Config): ORIGINS = "" MINUTES_BEFORE_TIMEOUT = "1" SECONDS_BETWEEN_SHUTDOWNS = "10" - PROJECT_FOLDER_PATH = "/project" class DevConfig(Config): diff --git a/src/opengeodeweb_back/geode_objects/geode_brep.py b/src/opengeodeweb_back/geode_objects/geode_brep.py index 98b2b481..38caa629 100644 --- a/src/opengeodeweb_back/geode_objects/geode_brep.py +++ b/src/opengeodeweb_back/geode_objects/geode_brep.py @@ -39,6 +39,7 @@ def builder(self) -> og.BRepBuilder: @classmethod def load(cls, filename: str) -> GeodeBRep: + print(f"Loading {filename}", flush=True) return GeodeBRep(og.load_brep(filename)) @classmethod @@ -65,6 +66,7 @@ def is_saveable(self, filename: str) -> bool: return og.is_brep_saveable(self.brep, filename) def save(self, filename: str) -> list[str]: + print(f"Saving {filename}", flush=True) return og.save_brep(self.brep, filename) def save_viewable(self, filename_without_extension: str) -> str: diff --git a/tests/conftest.py b/tests/conftest.py index 4d5ca51b..b2da434a 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -22,7 +22,7 @@ @pytest.fixture(scope="session", autouse=True) def configure_test_environment() -> Generator[None, None, None]: - base_path = Path(__file__).parent + base_path = Path(__file__).parent.absolute() test_data_path = base_path / "data" shutil.rmtree("./data", ignore_errors=True) @@ -30,7 +30,7 @@ def configure_test_environment() -> Generator[None, None, None]: app.config["TESTING"] = True app.config["SERVER_NAME"] = "TEST" - app.config["PROJECT_FOLDER_PATH"] = "./" + app.config["DATA_FOLDER_PATH"] = "./data/" app.config["UPLOAD_FOLDER_PATH"] = "./tests/data/" db_path = os.path.join(base_path, "data", "project.db") From 0fd41870e1eb4aecf4607ad1a375803006f5c1b0 Mon Sep 17 00:00:00 2001 From: JulienChampagnol Date: Mon, 29 Jun 2026 13:15:29 +0200 Subject: [PATCH 06/22] cleanup --- src/opengeodeweb_back/app_config.py | 5 ++++- src/opengeodeweb_back/geode_objects/geode_brep.py | 2 -- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/opengeodeweb_back/app_config.py b/src/opengeodeweb_back/app_config.py index a9299513..ca7af58d 100644 --- a/src/opengeodeweb_back/app_config.py +++ b/src/opengeodeweb_back/app_config.py @@ -5,6 +5,7 @@ # Third party imports # Local application imports +base_dir = os.path.dirname(os.path.abspath(__file__)) class Config(object): FLASK_DEBUG = os.environ.get("FLASK_DEBUG", default=False) @@ -33,4 +34,6 @@ class DevConfig(Config): ORIGINS = "*" MINUTES_BEFORE_TIMEOUT = "1" SECONDS_BETWEEN_SHUTDOWNS = "10" - PROJECT_FOLDER_PATH = os.path.dirname(os.path.abspath(__file__)) + PROJECT_FOLDER_PATH = base_dir + DATA_FOLDER_PATH = os.path.join(PROJECT_FOLDER_PATH, "data") + EXTENSIONS_FOLDER_PATH = os.path.join(PROJECT_FOLDER_PATH, "extensions") diff --git a/src/opengeodeweb_back/geode_objects/geode_brep.py b/src/opengeodeweb_back/geode_objects/geode_brep.py index 38caa629..98b2b481 100644 --- a/src/opengeodeweb_back/geode_objects/geode_brep.py +++ b/src/opengeodeweb_back/geode_objects/geode_brep.py @@ -39,7 +39,6 @@ def builder(self) -> og.BRepBuilder: @classmethod def load(cls, filename: str) -> GeodeBRep: - print(f"Loading {filename}", flush=True) return GeodeBRep(og.load_brep(filename)) @classmethod @@ -66,7 +65,6 @@ def is_saveable(self, filename: str) -> bool: return og.is_brep_saveable(self.brep, filename) def save(self, filename: str) -> list[str]: - print(f"Saving {filename}", flush=True) return og.save_brep(self.brep, filename) def save_viewable(self, filename_without_extension: str) -> str: From 8aa6ba5f024623e1866176e887548fd92ef77398 Mon Sep 17 00:00:00 2001 From: JulienChampagnol <91873154+JulienChampagnol@users.noreply.github.com> Date: Mon, 29 Jun 2026 13:07:27 +0000 Subject: [PATCH 07/22] Apply prepare changes --- tests/conftest.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/conftest.py b/tests/conftest.py index b2da434a..aaa059c2 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -22,7 +22,7 @@ @pytest.fixture(scope="session", autouse=True) def configure_test_environment() -> Generator[None, None, None]: - base_path = Path(__file__).parent.absolute() + base_path = Path(__file__).parent.absolute() test_data_path = base_path / "data" shutil.rmtree("./data", ignore_errors=True) From 66aed939959527e3bc70970e3f7f511ca05d282c Mon Sep 17 00:00:00 2001 From: JulienChampagnol Date: Mon, 29 Jun 2026 13:48:08 +0200 Subject: [PATCH 08/22] data_folder_path --- src/opengeodeweb_back/app.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/opengeodeweb_back/app.py b/src/opengeodeweb_back/app.py index 08773700..cbdc8c33 100644 --- a/src/opengeodeweb_back/app.py +++ b/src/opengeodeweb_back/app.py @@ -126,6 +126,13 @@ def run_server(app: Flask) -> None: default=app.config.get("PROJECT_FOLDER_PATH"), help="Path to the folder where the project is stored", ) + parser.add_argument( + "-dfp", + "--data_folder_path", + type=str, + default=app.config.get("DATA_FOLDER_PATH"), + help="Path to the folder where the data is stored", + ) parser.add_argument( "-ufp", "--upload_folder_path", From f9df05a4898daf39fba15de559460a321fe4cbd2 Mon Sep 17 00:00:00 2001 From: JulienChampagnol <91873154+JulienChampagnol@users.noreply.github.com> Date: Mon, 29 Jun 2026 13:16:05 +0000 Subject: [PATCH 09/22] Apply prepare changes --- src/opengeodeweb_back/app_config.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/opengeodeweb_back/app_config.py b/src/opengeodeweb_back/app_config.py index ca7af58d..b0569b37 100644 --- a/src/opengeodeweb_back/app_config.py +++ b/src/opengeodeweb_back/app_config.py @@ -7,6 +7,7 @@ base_dir = os.path.dirname(os.path.abspath(__file__)) + class Config(object): FLASK_DEBUG = os.environ.get("FLASK_DEBUG", default=False) HOST = "localhost" From 33027affe06fc02e01a6a8060b1b976a804ab7c5 Mon Sep 17 00:00:00 2001 From: JulienChampagnol Date: Mon, 29 Jun 2026 14:43:35 +0200 Subject: [PATCH 10/22] no default PROJECT_FOLDER_PATH --- src/opengeodeweb_back/app.py | 54 ++++++++++++++++------------- src/opengeodeweb_back/app_config.py | 15 ++++---- tests/conftest.py | 1 + 3 files changed, 39 insertions(+), 31 deletions(-) diff --git a/src/opengeodeweb_back/app.py b/src/opengeodeweb_back/app.py index cbdc8c33..6c68676f 100644 --- a/src/opengeodeweb_back/app.py +++ b/src/opengeodeweb_back/app.py @@ -18,15 +18,6 @@ def create_app(name: str) -> flask.Flask: app = flask.Flask(name) - """ Config variables """ - FLASK_DEBUG = ( - True if os.environ.get("FLASK_DEBUG", default=None) == "True" else False - ) - if FLASK_DEBUG == False: - app.config.from_object(app_config.ProdConfig) - else: - app.config.from_object(app_config.DevConfig) - @app.before_request def before_request() -> flask.Response | None: if flask.request.method == "OPTIONS": @@ -102,14 +93,12 @@ def run_server(app: Flask) -> None: parser.add_argument( "--host", type=str, - default=app.config.get("HOST"), help="Host to run on", ) parser.add_argument( "-p", "--port", type=int, - default=app.config.get("PORT"), help="Port to listen on", ) parser.add_argument( @@ -123,45 +112,62 @@ def run_server(app: Flask) -> None: "-pfp", "--project_folder_path", type=str, - default=app.config.get("PROJECT_FOLDER_PATH"), help="Path to the folder where the project is stored", ) parser.add_argument( "-dfp", "--data_folder_path", type=str, - default=app.config.get("DATA_FOLDER_PATH"), help="Path to the folder where the data is stored", ) parser.add_argument( "-ufp", "--upload_folder_path", type=str, - default=app.config.get("UPLOAD_FOLDER_PATH"), help="Path to the folder where uploads are stored", ) parser.add_argument( "-origins", "--allowed_origins", nargs="+", - default=app.config.get("ORIGINS"), help="Origins that are allowed to connect to the server", ) parser.add_argument( "-t", "--timeout", - default=app.config.get("MINUTES_BEFORE_TIMEOUT"), help="Number of minutes before the server times out", ) args, _ = parser.parse_known_args() - app.config.update(PROJECT_FOLDER_PATH=args.project_folder_path) - app.config.update(UPLOAD_FOLDER_PATH=args.upload_folder_path) - app.config.update(MINUTES_BEFORE_TIMEOUT=args.timeout) - flask_cors.CORS(app, origins=args.allowed_origins) print(f"{args=}", flush=True) + if not "project_folder_path" in args: + raise ValueError("project_folder_path must be provided") + if args.debug: + app.config.from_object(app_config.DevConfig(args.project_folder_path)) + else: + app.config.from_object(app_config.ProdConfig(args.project_folder_path)) + + if "host" in args: + app.config.update(HOST=args.host) + if "port" in args: + app.config.update(HOST=args.port) + if "debug" in args: + app.config.update(FLASK_DEBUG=args.debug) + if "data_folder_path" in args: + app.config.update(DATA_FOLDER_PATH=args.data_folder_path) + if "upload_folder_path" in args: + app.config.update(UPLOAD_FOLDER_PATH=args.upload_folder_path) + if "allowed_origins" in args: + app.config.update(ALLOWED_ORIGINS=args.allowed_origins) + if "timeout" in args: + app.config.update(MINUTES_BEFORE_TIMEOUT=args.timeout) + + + + + db_filename: str = app.config.get("DATABASE_FILENAME") or "project.db" - db_path = os.path.join(str(args.data_folder_path), db_filename) + db_path = os.path.join(str(app.config.get("DATA_FOLDER_PATH")), db_filename) os.makedirs(os.path.dirname(db_path), exist_ok=True) app.config["SQLALCHEMY_DATABASE_URI"] = f"sqlite:///{db_path}" app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False @@ -169,9 +175,9 @@ def run_server(app: Flask) -> None: connection.init_database(db_path) print(f"Database initialized at: {db_path}", flush=True) app.run( - debug=args.debug, - host=args.host, - port=args.port, + debug=app.config.get("FLASK_DEBUG"), + host=app.config.get("HOST"), + port=app.config.get("PORT"), ssl_context=app.config.get("SSL"), ) diff --git a/src/opengeodeweb_back/app_config.py b/src/opengeodeweb_back/app_config.py index b0569b37..0b12083c 100644 --- a/src/opengeodeweb_back/app_config.py +++ b/src/opengeodeweb_back/app_config.py @@ -13,15 +13,18 @@ class Config(object): HOST = "localhost" PORT = "5000" CORS_HEADERS = "Content-Type" - PROJECT_FOLDER_PATH = "/project" - DATA_FOLDER_PATH = os.path.join(PROJECT_FOLDER_PATH, "data") - EXTENSIONS_FOLDER_PATH = os.path.join(PROJECT_FOLDER_PATH, "exensions") - UPLOAD_FOLDER_PATH = os.path.join(PROJECT_FOLDER_PATH, "uploads") REQUEST_COUNTER = 0 LAST_REQUEST_TIME = time.time() LAST_PING_TIME = time.time() DATABASE_FILENAME = "project.db" + def __init__(self, project_folder_path: str): + self.PROJECT_FOLDER_PATH = project_folder_path + self.DATA_FOLDER_PATH = os.path.join(project_folder_path, "data") + self.EXTENSIONS_FOLDER_PATH = os.path.join(project_folder_path, "extensions") + self.UPLOAD_FOLDER_PATH = os.path.join(project_folder_path, "uploads") + self.EXTENSIONS_FOLDER_PATH = os.path.join(project_folder_path, "extensions") + class ProdConfig(Config): SSL = None @@ -30,11 +33,9 @@ class ProdConfig(Config): SECONDS_BETWEEN_SHUTDOWNS = "10" + class DevConfig(Config): SSL = None ORIGINS = "*" MINUTES_BEFORE_TIMEOUT = "1" SECONDS_BETWEEN_SHUTDOWNS = "10" - PROJECT_FOLDER_PATH = base_dir - DATA_FOLDER_PATH = os.path.join(PROJECT_FOLDER_PATH, "data") - EXTENSIONS_FOLDER_PATH = os.path.join(PROJECT_FOLDER_PATH, "extensions") diff --git a/tests/conftest.py b/tests/conftest.py index aaa059c2..e558da8f 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -30,6 +30,7 @@ def configure_test_environment() -> Generator[None, None, None]: app.config["TESTING"] = True app.config["SERVER_NAME"] = "TEST" + app.config["PROJECT_FOLDER_PATH"] = base_path app.config["DATA_FOLDER_PATH"] = "./data/" app.config["UPLOAD_FOLDER_PATH"] = "./tests/data/" From 08abfefc9ce63e19bf549e3df8371ef462009f99 Mon Sep 17 00:00:00 2001 From: JulienChampagnol Date: Mon, 29 Jun 2026 14:43:45 +0200 Subject: [PATCH 11/22] no default PROJECT_FOLDER_PATH --- src/opengeodeweb_back/app_config.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/opengeodeweb_back/app_config.py b/src/opengeodeweb_back/app_config.py index 0b12083c..9a71a86b 100644 --- a/src/opengeodeweb_back/app_config.py +++ b/src/opengeodeweb_back/app_config.py @@ -23,7 +23,6 @@ def __init__(self, project_folder_path: str): self.DATA_FOLDER_PATH = os.path.join(project_folder_path, "data") self.EXTENSIONS_FOLDER_PATH = os.path.join(project_folder_path, "extensions") self.UPLOAD_FOLDER_PATH = os.path.join(project_folder_path, "uploads") - self.EXTENSIONS_FOLDER_PATH = os.path.join(project_folder_path, "extensions") class ProdConfig(Config): From fa87897a4790ccf65d11eae6f59db60219ec22db Mon Sep 17 00:00:00 2001 From: JulienChampagnol <91873154+JulienChampagnol@users.noreply.github.com> Date: Mon, 29 Jun 2026 14:44:27 +0000 Subject: [PATCH 12/22] Apply prepare changes --- src/opengeodeweb_back/app.py | 9 ++------- src/opengeodeweb_back/app_config.py | 1 - 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/src/opengeodeweb_back/app.py b/src/opengeodeweb_back/app.py index 6c68676f..97d1db9f 100644 --- a/src/opengeodeweb_back/app.py +++ b/src/opengeodeweb_back/app.py @@ -147,9 +147,9 @@ def run_server(app: Flask) -> None: app.config.from_object(app_config.ProdConfig(args.project_folder_path)) if "host" in args: - app.config.update(HOST=args.host) + app.config.update(HOST=args.host) if "port" in args: - app.config.update(HOST=args.port) + app.config.update(HOST=args.port) if "debug" in args: app.config.update(FLASK_DEBUG=args.debug) if "data_folder_path" in args: @@ -160,11 +160,6 @@ def run_server(app: Flask) -> None: app.config.update(ALLOWED_ORIGINS=args.allowed_origins) if "timeout" in args: app.config.update(MINUTES_BEFORE_TIMEOUT=args.timeout) - - - - - db_filename: str = app.config.get("DATABASE_FILENAME") or "project.db" db_path = os.path.join(str(app.config.get("DATA_FOLDER_PATH")), db_filename) diff --git a/src/opengeodeweb_back/app_config.py b/src/opengeodeweb_back/app_config.py index 9a71a86b..6ff32ef4 100644 --- a/src/opengeodeweb_back/app_config.py +++ b/src/opengeodeweb_back/app_config.py @@ -32,7 +32,6 @@ class ProdConfig(Config): SECONDS_BETWEEN_SHUTDOWNS = "10" - class DevConfig(Config): SSL = None ORIGINS = "*" From 6c4278cdd449c8bff6e24ef715db74bb5eb874fc Mon Sep 17 00:00:00 2001 From: JulienChampagnol Date: Tue, 30 Jun 2026 09:25:26 +0200 Subject: [PATCH 13/22] cleanup --- src/opengeodeweb_back/app.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/opengeodeweb_back/app.py b/src/opengeodeweb_back/app.py index 6c68676f..2c7229f3 100644 --- a/src/opengeodeweb_back/app.py +++ b/src/opengeodeweb_back/app.py @@ -139,6 +139,7 @@ def run_server(app: Flask) -> None: ) args, _ = parser.parse_known_args() print(f"{args=}", flush=True) + if not "project_folder_path" in args: raise ValueError("project_folder_path must be provided") if args.debug: @@ -161,12 +162,7 @@ def run_server(app: Flask) -> None: if "timeout" in args: app.config.update(MINUTES_BEFORE_TIMEOUT=args.timeout) - - - - - - db_filename: str = app.config.get("DATABASE_FILENAME") or "project.db" + db_filename: str = app.config.get("DATABASE_FILENAME") db_path = os.path.join(str(app.config.get("DATA_FOLDER_PATH")), db_filename) os.makedirs(os.path.dirname(db_path), exist_ok=True) app.config["SQLALCHEMY_DATABASE_URI"] = f"sqlite:///{db_path}" From 8cc79d04f435c58b733fd051f0bece673e233419 Mon Sep 17 00:00:00 2001 From: JulienChampagnol Date: Tue, 30 Jun 2026 09:35:40 +0200 Subject: [PATCH 14/22] port type str --- src/opengeodeweb_back/app.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/opengeodeweb_back/app.py b/src/opengeodeweb_back/app.py index d358e106..e9b94e97 100644 --- a/src/opengeodeweb_back/app.py +++ b/src/opengeodeweb_back/app.py @@ -98,7 +98,7 @@ def run_server(app: Flask) -> None: parser.add_argument( "-p", "--port", - type=int, + type=str, help="Port to listen on", ) parser.add_argument( From f96a879d7e908bd4d6b93ec4c6c2c4ce2d7e193f Mon Sep 17 00:00:00 2001 From: JulienChampagnol <91873154+JulienChampagnol@users.noreply.github.com> Date: Tue, 30 Jun 2026 09:26:12 +0000 Subject: [PATCH 15/22] Apply prepare changes --- src/opengeodeweb_back/app.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/opengeodeweb_back/app.py b/src/opengeodeweb_back/app.py index d358e106..9217a092 100644 --- a/src/opengeodeweb_back/app.py +++ b/src/opengeodeweb_back/app.py @@ -161,7 +161,7 @@ def run_server(app: Flask) -> None: app.config.update(ALLOWED_ORIGINS=args.allowed_origins) if "timeout" in args: app.config.update(MINUTES_BEFORE_TIMEOUT=args.timeout) - + db_filename: str = app.config.get("DATABASE_FILENAME") db_path = os.path.join(str(app.config.get("DATA_FOLDER_PATH")), db_filename) os.makedirs(os.path.dirname(db_path), exist_ok=True) From cc2f75c5b13b56b1b1a6f580e192777a3c841597 Mon Sep 17 00:00:00 2001 From: JulienChampagnol Date: Tue, 30 Jun 2026 09:41:47 +0200 Subject: [PATCH 16/22] typo --- src/opengeodeweb_back/app.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/opengeodeweb_back/app.py b/src/opengeodeweb_back/app.py index 93668580..0990a4ee 100644 --- a/src/opengeodeweb_back/app.py +++ b/src/opengeodeweb_back/app.py @@ -150,7 +150,7 @@ def run_server(app: Flask) -> None: if "host" in args: app.config.update(HOST=args.host) if "port" in args: - app.config.update(HOST=args.port) + app.config.update(PORT=args.port) if "debug" in args: app.config.update(FLASK_DEBUG=args.debug) if "data_folder_path" in args: From 89ef51114dc73dd513c3034f7e21ffc7baac3a4b Mon Sep 17 00:00:00 2001 From: JulienChampagnol Date: Tue, 30 Jun 2026 09:47:58 +0200 Subject: [PATCH 17/22] mypy --- src/opengeodeweb_back/app.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/opengeodeweb_back/app.py b/src/opengeodeweb_back/app.py index 0990a4ee..34d0e75e 100644 --- a/src/opengeodeweb_back/app.py +++ b/src/opengeodeweb_back/app.py @@ -162,7 +162,9 @@ def run_server(app: Flask) -> None: if "timeout" in args: app.config.update(MINUTES_BEFORE_TIMEOUT=args.timeout) - db_filename: str = app.config.get("DATABASE_FILENAME") + db_filename = app.config.get("DATABASE_FILENAME") + if not isinstance(db_filename, str): + raise TypeError(f"DATABASE_FILENAME config must be a string, got {db_filename!r}") db_path = os.path.join(str(app.config.get("DATA_FOLDER_PATH")), db_filename) os.makedirs(os.path.dirname(db_path), exist_ok=True) app.config["SQLALCHEMY_DATABASE_URI"] = f"sqlite:///{db_path}" From bb483468e85361a95664180b7d36712a68a8c545 Mon Sep 17 00:00:00 2001 From: JulienChampagnol Date: Tue, 30 Jun 2026 10:38:20 +0200 Subject: [PATCH 18/22] update config & abspath project_folder_path --- src/opengeodeweb_back/app.py | 46 +++++++++++++++++++++++++++++------- 1 file changed, 37 insertions(+), 9 deletions(-) diff --git a/src/opengeodeweb_back/app.py b/src/opengeodeweb_back/app.py index 34d0e75e..69c0528e 100644 --- a/src/opengeodeweb_back/app.py +++ b/src/opengeodeweb_back/app.py @@ -135,32 +135,60 @@ def run_server(app: Flask) -> None: parser.add_argument( "-t", "--timeout", + help="Number of minutes before the server times out", ) args, _ = parser.parse_known_args() - print(f"{args=}", flush=True) - if not "project_folder_path" in args: + + + if args.project_folder_path is None: raise ValueError("project_folder_path must be provided") + else: + args.project_folder_path = os.path.abspath(args.project_folder_path) + if args.debug: app.config.from_object(app_config.DevConfig(args.project_folder_path)) else: app.config.from_object(app_config.ProdConfig(args.project_folder_path)) - if "host" in args: + print(app.config, flush=True) + if args.host is not None: app.config.update(HOST=args.host) - if "port" in args: + else: + args.host = app.config.get("HOST") + + if args.port is not None: app.config.update(PORT=args.port) - if "debug" in args: + else: + args.port = app.config.get("PORT") + + if args.debug is not None: app.config.update(FLASK_DEBUG=args.debug) - if "data_folder_path" in args: + else: + args.debug = app.config.get("FLASK_DEBUG") + + if args.data_folder_path is not None: app.config.update(DATA_FOLDER_PATH=args.data_folder_path) - if "upload_folder_path" in args: + else: + args.data_folder_path = app.config.get("DATA_FOLDER_PATH") + + if args.upload_folder_path is not None: app.config.update(UPLOAD_FOLDER_PATH=args.upload_folder_path) - if "allowed_origins" in args: + else: + args.upload_folder_path = app.config.get("UPLOAD_FOLDER_PATH") + + if args.allowed_origins is not None: app.config.update(ALLOWED_ORIGINS=args.allowed_origins) - if "timeout" in args: + else: + args.allowed_origins = app.config.get("ALLOWED_ORIGINS") + + if args.timeout is not None: app.config.update(MINUTES_BEFORE_TIMEOUT=args.timeout) + else: + args.timeout = app.config.get("MINUTES_BEFORE_TIMEOUT") + + print(f"{args=}", flush=True) db_filename = app.config.get("DATABASE_FILENAME") if not isinstance(db_filename, str): From e55966e7c652ac85bae14570e4f353261b6bdbd0 Mon Sep 17 00:00:00 2001 From: JulienChampagnol <91873154+JulienChampagnol@users.noreply.github.com> Date: Tue, 30 Jun 2026 09:48:45 +0000 Subject: [PATCH 19/22] Apply prepare changes --- src/opengeodeweb_back/app.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/opengeodeweb_back/app.py b/src/opengeodeweb_back/app.py index 34d0e75e..304333d7 100644 --- a/src/opengeodeweb_back/app.py +++ b/src/opengeodeweb_back/app.py @@ -164,7 +164,9 @@ def run_server(app: Flask) -> None: db_filename = app.config.get("DATABASE_FILENAME") if not isinstance(db_filename, str): - raise TypeError(f"DATABASE_FILENAME config must be a string, got {db_filename!r}") + raise TypeError( + f"DATABASE_FILENAME config must be a string, got {db_filename!r}" + ) db_path = os.path.join(str(app.config.get("DATA_FOLDER_PATH")), db_filename) os.makedirs(os.path.dirname(db_path), exist_ok=True) app.config["SQLALCHEMY_DATABASE_URI"] = f"sqlite:///{db_path}" From 74fc6a606acd22627502389bc84131e34706d020 Mon Sep 17 00:00:00 2001 From: JulienChampagnol Date: Tue, 30 Jun 2026 10:51:08 +0200 Subject: [PATCH 20/22] cleanup --- src/opengeodeweb_back/app.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/opengeodeweb_back/app.py b/src/opengeodeweb_back/app.py index 98d24d11..d69af69f 100644 --- a/src/opengeodeweb_back/app.py +++ b/src/opengeodeweb_back/app.py @@ -152,7 +152,6 @@ def run_server(app: Flask) -> None: else: app.config.from_object(app_config.ProdConfig(args.project_folder_path)) - print(app.config, flush=True) if args.host is not None: app.config.update(HOST=args.host) else: From 718bede6a6911245cbdc65b1ad1c9ec88dec3c6b Mon Sep 17 00:00:00 2001 From: JulienChampagnol <91873154+JulienChampagnol@users.noreply.github.com> Date: Tue, 30 Jun 2026 10:38:56 +0000 Subject: [PATCH 21/22] Apply prepare changes --- src/opengeodeweb_back/app.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/opengeodeweb_back/app.py b/src/opengeodeweb_back/app.py index 98d24d11..5bd2ed2c 100644 --- a/src/opengeodeweb_back/app.py +++ b/src/opengeodeweb_back/app.py @@ -135,13 +135,10 @@ def run_server(app: Flask) -> None: parser.add_argument( "-t", "--timeout", - help="Number of minutes before the server times out", ) args, _ = parser.parse_known_args() - - if args.project_folder_path is None: raise ValueError("project_folder_path must be provided") else: From 6d5995a48772479a4c9731fed105f189772e4509 Mon Sep 17 00:00:00 2001 From: JulienChampagnol Date: Tue, 30 Jun 2026 14:46:46 +0200 Subject: [PATCH 22/22] CORS --- src/opengeodeweb_back/app.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/opengeodeweb_back/app.py b/src/opengeodeweb_back/app.py index a6451298..a3105a73 100644 --- a/src/opengeodeweb_back/app.py +++ b/src/opengeodeweb_back/app.py @@ -198,6 +198,8 @@ def run_server(app: Flask) -> None: connection.init_database(db_path) print(f"Database initialized at: {db_path}", flush=True) + + flask_cors.CORS(app, origins=args.allowed_origins) app.run( debug=app.config.get("FLASK_DEBUG"), host=app.config.get("HOST"),