Refactor library structure detection to use enum values and update related tests and frontend logic

This commit is contained in:
zurdi
2026-01-02 11:54:29 +00:00
parent 06a1598bcc
commit cc816822d8
7 changed files with 36 additions and 38 deletions

View File

@@ -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

View File

@@ -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"),

View File

@@ -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

View File

@@ -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"

View File

@@ -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(

View File

@@ -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;

View File

@@ -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(() => {
<p class="text-white text-shadow">
<strong>{{ t("setup.folder-structure") }}:</strong>
{{
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")
}}
</p>
<p class="text-caption text-grey">
{{
libraryInfo?.detected_structure === "A" ||
libraryInfo?.detected_structure === "struct_a" ||
!libraryInfo?.detected_structure
? "roms/{platform}"
: "{platform}/roms"