From 39548a235e2d767d3f6952b37aef7f25753cf57b Mon Sep 17 00:00:00 2001 From: Antoine Nguyen Date: Thu, 31 Jul 2025 13:47:58 +0200 Subject: [PATCH] Added option to use relative urls for generated config file --- .../management/commands/load_initial_data.py | 39 +++++++++++--- modoboa/core/tests/test_core.py | 53 ++++++++++++++++--- 2 files changed, 78 insertions(+), 14 deletions(-) diff --git a/modoboa/core/management/commands/load_initial_data.py b/modoboa/core/management/commands/load_initial_data.py index d5984fa5a..54bf2620f 100644 --- a/modoboa/core/management/commands/load_initial_data.py +++ b/modoboa/core/management/commands/load_initial_data.py @@ -57,6 +57,12 @@ class Command(BaseCommand): default=False, help="Omit everything related to frontend initialisation", ) + parser.add_argument( + "--relative-urls-in-config", + action="store_true", + default=False, + help="Use relative urls in generated config.json file", + ) def handle(self, *args, **options): """Command entry point.""" @@ -117,7 +123,10 @@ class Command(BaseCommand): base_uris = " ".join(base_uris_list) base_uri = base_uris_list[0] redirect_uris = " ".join([f"{uri}/login/logged" for uri in base_uris_list]) - redirect_uri = redirect_uris.split(" ")[0] + if not options["relative_urls_in_config"]: + redirect_uri = redirect_uris.split(" ")[0] + else: + redirect_uri = "/login/logged" client_id = "" if options["dev"]: base_uri = "https://localhost:3000/" @@ -151,9 +160,11 @@ class Command(BaseCommand): ) frontend_target_dir = f"{settings.BASE_DIR}/frontend" if hasattr(settings, "MODOBOA_CUSTOM_LOGO"): - logo_path = settings.MODOBOA_CUSTOM_LOGO + menu_logo_path = settings.MODOBOA_CUSTOM_LOGO + form_logo_path = settings.MODOBOA_CUSTOM_LOGO else: - logo_path = f"{frontend_target_dir}/assets/Modoboa_RVB-BLANC-SANS.png" + menu_logo_path = f"{frontend_target_dir}/assets/Modoboa_RVB-BLANC-SANS.png" + form_logo_path = f"{frontend_target_dir}/assets/Modoboa_RVB-BLEU-SANS.png" if os.path.isdir(base_frontend_dir): shutil.rmtree(frontend_target_dir, ignore_errors=True) os.makedirs(frontend_target_dir, exist_ok=True) @@ -164,16 +175,28 @@ class Command(BaseCommand): f"{frontend_target_dir}/{entry.name}", target_is_directory=entry.is_dir(), ) + api_base_url = "/api/v2" + api_doc_url = "/api/schema-v2/swagger/" + oauth_authority_url = "/api/o" + if options["relative_urls_in_config"]: + api_base_url += base_uri + api_doc_url += base_uri + oauth_authority_url += base_uri + oauth_post_logout_redirect_uri = "" + else: + oauth_post_logout_redirect_uri = base_uri + with open(f"{frontend_target_dir}/config.json", "w") as fp: fp.write( f"""{{ - "API_BASE_URL": "{base_uri}/api/v2", - "API_DOC_URL": "{base_uri}/api/schema-v2/swagger/", - "OAUTH_AUTHORITY_URL": "{base_uri}/api/o", + "API_BASE_URL": "{api_base_url}", + "API_DOC_URL": "{api_doc_url}", + "OAUTH_AUTHORITY_URL": "{oauth_authority_url}", "OAUTH_CLIENT_ID": "{client_id}", "OAUTH_REDIRECT_URI": "{redirect_uri}", - "OAUTH_POST_REDIRECT_URI": "{base_uri}", - "MENU_LOGO_PATH": "{logo_path}" + "OAUTH_POST_REDIRECT_URI": "{oauth_post_logout_redirect_uri}", + "MENU_LOGO_PATH": "{menu_logo_path}", + "CREATION_FORM_LOGO_PATH": "{form_logo_path}" }} """ ) diff --git a/modoboa/core/tests/test_core.py b/modoboa/core/tests/test_core.py index c9a086a81..e234ad88a 100644 --- a/modoboa/core/tests/test_core.py +++ b/modoboa/core/tests/test_core.py @@ -86,20 +86,61 @@ class ManagementCommandsTestCase(SimpleModoTestCase): self.addCleanup(shutil.rmtree, frontend_src) frontend_dir = pathlib.Path(settings.BASE_DIR) / "frontend" - self.assertFalse(frontend_dir.exists(), f"frontend directory {frontend_dir} doesn’t exist before load_initial_data") + self.assertFalse( + frontend_dir.exists(), + f"frontend directory {frontend_dir} doesn’t exist before load_initial_data", + ) management.call_command("load_initial_data") - self.assertTrue(frontend_dir.is_dir(), f"frontend directory {frontend_dir} is directory after load_initial_data") + self.assertTrue( + frontend_dir.is_dir(), + f"frontend directory {frontend_dir} is directory after load_initial_data", + ) for entry in frontend_dir.iterdir(): if entry.name == "config.json": - self.assertTrue(entry.is_file() and not entry.is_symlink(), f"frontend directory entry {entry} is regular file") + self.assertTrue( + entry.is_file() and not entry.is_symlink(), + f"frontend directory entry {entry} is regular file", + ) try: content = json.loads(entry.read_text("utf-8")) except (ValueError, UnicodeDecodeError): - self.fail(f"frontend directory entry {entry} is not UTF-8 encoded JSON") - for key_name in ("API_BASE_URL", "OAUTH_AUTHORITY_URL", "OAUTH_CLIENT_ID", "OAUTH_REDIRECT_URI", "OAUTH_POST_REDIRECT_URI"): + self.fail( + f"frontend directory entry {entry} is not UTF-8 encoded JSON" + ) + for key_name in ( + "API_BASE_URL", + "OAUTH_AUTHORITY_URL", + "OAUTH_CLIENT_ID", + "OAUTH_REDIRECT_URI", + "OAUTH_POST_REDIRECT_URI", + ): self.assertIn(key_name, content) else: - self.assertTrue(entry.is_symlink(), f"frontend directory entry {entry} is symlink") + self.assertTrue( + entry.is_symlink(), f"frontend directory entry {entry} is symlink" + ) + + def test_init_data_relative_urls(self): + """Test behavior of --relative-urls-in-config option.""" + # Create our own dummy frontend directory if `vite` hasn’t been invoked yet + frontend_src = pathlib.Path(__file__).parent.parent.parent / "frontend_dist" + if not frontend_src.is_dir(): + (frontend_src / "dummy").mkdir(parents=True) + self.addCleanup(shutil.rmtree, frontend_src) + + management.call_command("load_initial_data", "--relative-urls-in-config") + frontend_dir = pathlib.Path(settings.BASE_DIR) / "frontend" + filepath = f"{frontend_dir}/config.json" + self.assertTrue(frontend_dir.exists()) + with open(filepath) as fp: + config = json.loads(fp.read()) + for param in [ + "API_BASE_URL", + "API_DOC_URL", + "OAUTH_REDIRECT_URI", + "OAUTH_POST_REDIRECT_URI", + ]: + self.assertFalse(config[param].startswith("http")) def test_clean_inactive_accounts(self): """Run clean_inactive_accounts command."""