From cc816822d83937cd0ebe2a9b01d0f47bd7bdf076 Mon Sep 17 00:00:00 2001 From: zurdi Date: Fri, 2 Jan 2026 11:54:29 +0000 Subject: [PATCH] Refactor library structure detection to use enum values and update related tests and frontend logic --- backend/endpoints/heartbeat.py | 10 +++--- backend/handler/filesystem/base_handler.py | 6 ++++ .../handler/filesystem/platforms_handler.py | 32 ++++++++----------- backend/tests/endpoints/test_heartbeat.py | 14 ++++---- .../filesystem/test_platforms_handler.py | 2 +- frontend/src/services/api/setup.ts | 2 +- frontend/src/views/Auth/Setup.vue | 8 ++--- 7 files changed, 36 insertions(+), 38 deletions(-) diff --git a/backend/endpoints/heartbeat.py b/backend/endpoints/heartbeat.py index 6b58a16c6..cdf11c556 100644 --- a/backend/endpoints/heartbeat.py +++ b/backend/endpoints/heartbeat.py @@ -177,7 +177,7 @@ async def get_setup_library_info(request: Request): Only accessible during initial setup (no admin users) or with authentication. Returns: - - detected_structure: "A" (roms/{platform}), "B" ({platform}/roms), or None + - detected_structure: "struct_a" (roms/{platform}), "struct_b" ({platform}/roms), or None - existing_platforms: list of objects with fs_slug and rom_count - supported_platforms: list of all supported platforms with metadata """ @@ -215,7 +215,7 @@ async def get_setup_library_info(request: Request): rom_count = 0 try: # Determine the roms directory based on structure - if detected_structure == "A": + if detected_structure == "struct_a": roms_path = os.path.join( LIBRARY_BASE_PATH, cnfg.ROMS_FOLDER_NAME, fs_slug ) @@ -299,11 +299,9 @@ async def create_setup_platforms(request: Request, platform_slugs: list[str]): # Detect structure type to determine if we need to create the roms folder detected_structure = fs_platform_handler.detect_library_structure() - # If no structure detected, create structure A (roms folder) + # If no structure detected, create structure A if detected_structure is None: - cnfg = cm.get_config() - roms_path = os.path.join(LIBRARY_BASE_PATH, cnfg.ROMS_FOLDER_NAME) - os.makedirs(roms_path, exist_ok=True) + fs_platform_handler.create_library_structure() # Create platform folders created_count = 0 diff --git a/backend/handler/filesystem/base_handler.py b/backend/handler/filesystem/base_handler.py index 149cff719..5e48e41cd 100644 --- a/backend/handler/filesystem/base_handler.py +++ b/backend/handler/filesystem/base_handler.py @@ -24,6 +24,12 @@ UUID_V4_REGEX = re.compile( re.IGNORECASE, ) + +class LibraryStructure(Enum): + A = "struct_a" + B = "struct_b" + + LANGUAGES = ( ("Ar", "Arabic"), ("Da", "Danish"), diff --git a/backend/handler/filesystem/platforms_handler.py b/backend/handler/filesystem/platforms_handler.py index abf23c373..f95558a0d 100644 --- a/backend/handler/filesystem/platforms_handler.py +++ b/backend/handler/filesystem/platforms_handler.py @@ -7,7 +7,7 @@ from exceptions.fs_exceptions import ( PlatformAlreadyExistsException, ) -from .base_handler import FSHandler +from .base_handler import FSHandler, LibraryStructure class FSPlatformsHandler(FSHandler): @@ -22,12 +22,18 @@ class FSPlatformsHandler(FSHandler): if platform not in cnfg.EXCLUDED_PLATFORMS ] - def detect_library_structure(self) -> str | None: + def create_library_structure(self) -> None: + """Creates the library structure with a roms folder.""" + cnfg = cm.get_config() + roms_path = os.path.join(LIBRARY_BASE_PATH, cnfg.ROMS_FOLDER_NAME) + os.makedirs(roms_path, exist_ok=True) + + def detect_library_structure(self) -> LibraryStructure | None: """Detects the library structure type. Returns: - "A" for Structure A (roms/{platform}) - "B" for Structure B ({platform}/roms) + "LibraryStructure.A" for Structure A (roms/{platform}) + "LibraryStructure.B" for Structure B ({platform}/roms) None if no structure detected """ cnfg = cm.get_config() @@ -35,7 +41,7 @@ class FSPlatformsHandler(FSHandler): # Check if the roms folder exists (Structure A indicator) roms_path = os.path.join(LIBRARY_BASE_PATH, cnfg.ROMS_FOLDER_NAME) if os.path.exists(roms_path): - return "A" + return LibraryStructure.A # Check if any platform folders with roms subfolders exist (Structure B) try: @@ -44,7 +50,7 @@ class FSPlatformsHandler(FSHandler): item_path = os.path.join(LIBRARY_BASE_PATH, item) roms_subfolder = os.path.join(item_path, cnfg.ROMS_FOLDER_NAME) if os.path.isdir(item_path) and os.path.exists(roms_subfolder): - return "B" + return LibraryStructure.B except (OSError, FileNotFoundError): pass @@ -53,12 +59,6 @@ class FSPlatformsHandler(FSHandler): def get_platforms_directory(self) -> str: cnfg = cm.get_config() - structure = self.detect_library_structure() - if structure == "A": - return cnfg.ROMS_FOLDER_NAME - if structure == "B": - return "" - # Fallback to config hint when detection is inconclusive return ( cnfg.ROMS_FOLDER_NAME @@ -69,12 +69,6 @@ class FSPlatformsHandler(FSHandler): def get_platform_fs_structure(self, fs_slug: str) -> str: cnfg = cm.get_config() - structure = self.detect_library_structure() - if structure == "A": - return f"{cnfg.ROMS_FOLDER_NAME}/{fs_slug}" - if structure == "B": - return f"{fs_slug}/{cnfg.ROMS_FOLDER_NAME}" - # Fallback to config hint when detection is inconclusive return ( f"{cnfg.ROMS_FOLDER_NAME}/{fs_slug}" @@ -110,7 +104,7 @@ class FSPlatformsHandler(FSHandler): # For Structure B, only include directories that have a roms subfolder structure = self.detect_library_structure() - if structure == "B": + if structure == LibraryStructure.B: platforms = [ platform for platform in platforms diff --git a/backend/tests/endpoints/test_heartbeat.py b/backend/tests/endpoints/test_heartbeat.py index 1cfb75ce7..4207bc191 100644 --- a/backend/tests/endpoints/test_heartbeat.py +++ b/backend/tests/endpoints/test_heartbeat.py @@ -73,12 +73,12 @@ def test_heartbeat_metadata_unknown_source(client): assert response.status_code == status.HTTP_400_BAD_REQUEST -def test_get_setup_library_info_structure_a_detected(client, admin_user, access_token): +def test_get_setup_library_info_structure_a_detected(client, access_token): """Test get_setup_library_info with Structure A detected""" with patch( "endpoints.heartbeat.fs_platform_handler.detect_library_structure" ) as mock_detect: - mock_detect.return_value = "A" + mock_detect.return_value = "struct_a" with patch( "endpoints.heartbeat.fs_platform_handler.get_platforms" @@ -100,7 +100,7 @@ def test_get_setup_library_info_structure_a_detected(client, admin_user, access_ assert response.status_code == status.HTTP_200_OK data = response.json() - assert data["detected_structure"] == "A" + assert data["detected_structure"] == "struct_a" assert len(data["existing_platforms"]) == 2 assert data["existing_platforms"][0]["fs_slug"] == "n64" assert data["existing_platforms"][0]["rom_count"] == 2 @@ -169,7 +169,7 @@ def test_get_setup_library_info_handles_errors(client, admin_user, access_token) with patch( "endpoints.heartbeat.fs_platform_handler.detect_library_structure" ) as mock_detect: - mock_detect.return_value = "A" + mock_detect.return_value = "struct_a" with patch( "endpoints.heartbeat.fs_platform_handler.get_platforms" @@ -196,7 +196,7 @@ def test_create_setup_platforms_success(client, admin_user, access_token): with patch( "endpoints.heartbeat.fs_platform_handler.detect_library_structure" ) as mock_detect: - mock_detect.return_value = "A" + mock_detect.return_value = "struct_a" with patch( "endpoints.heartbeat.fs_platform_handler.add_platform" @@ -268,7 +268,7 @@ def test_create_setup_platforms_skips_existing_platforms( with patch( "endpoints.heartbeat.fs_platform_handler.detect_library_structure" ) as mock_detect: - mock_detect.return_value = "A" + mock_detect.return_value = "struct_a" with patch( "endpoints.heartbeat.fs_platform_handler.add_platform" @@ -303,7 +303,7 @@ def test_create_setup_platforms_handles_permission_errors( with patch( "endpoints.heartbeat.fs_platform_handler.detect_library_structure" ) as mock_detect: - mock_detect.return_value = "A" + mock_detect.return_value = "struct_a" with patch( "endpoints.heartbeat.fs_platform_handler.add_platform" diff --git a/backend/tests/handler/filesystem/test_platforms_handler.py b/backend/tests/handler/filesystem/test_platforms_handler.py index 9913b8e70..3718c6172 100644 --- a/backend/tests/handler/filesystem/test_platforms_handler.py +++ b/backend/tests/handler/filesystem/test_platforms_handler.py @@ -325,7 +325,7 @@ class TestFSPlatformsHandler: mock_exists.return_value = True result = handler.detect_library_structure() - assert result == "A" + assert result == "struct_a" mock_exists.assert_called_once_with(roms_path) def test_detect_library_structure_structure_b( diff --git a/frontend/src/services/api/setup.ts b/frontend/src/services/api/setup.ts index d057b543c..77c23ebd1 100644 --- a/frontend/src/services/api/setup.ts +++ b/frontend/src/services/api/setup.ts @@ -1,7 +1,7 @@ import api from "@/services/api"; import type { Platform } from "@/stores/platforms"; -export type LibraryStructure = "A" | "B" | null; +export type LibraryStructure = "struct_a" | "struct_b" | null; export interface ExistingPlatform { fs_slug: string; diff --git a/frontend/src/views/Auth/Setup.vue b/frontend/src/views/Auth/Setup.vue index b569de49b..7b56f0719 100644 --- a/frontend/src/views/Auth/Setup.vue +++ b/frontend/src/views/Auth/Setup.vue @@ -331,7 +331,7 @@ function handleNext(nextCallback: () => void) { // Case 3: Structure is detected and user selected at least one platform to create if (hasStructure && platformsToCreate.length > 0 && libraryInfo.value) { const structurePattern = - libraryInfo.value.detected_structure === "A" + libraryInfo.value.detected_structure === "struct_a" ? "roms/{platform}" : "{platform}/roms"; confirmDialogMessage.value = t("setup.confirm-create-platforms", { @@ -526,16 +526,16 @@ onMounted(() => {

{{ t("setup.folder-structure") }}: {{ - libraryInfo?.detected_structure === "A" + libraryInfo?.detected_structure === "struct_a" ? t("setup.structure-a-detected") - : libraryInfo?.detected_structure === "B" + : libraryInfo?.detected_structure === "struct_b" ? t("setup.structure-b-detected") : t("setup.no-structure-detected") }}

{{ - libraryInfo?.detected_structure === "A" || + libraryInfo?.detected_structure === "struct_a" || !libraryInfo?.detected_structure ? "roms/{platform}" : "{platform}/roms"