Add typed RomUserData model for documented partial ROM user props update

Co-authored-by: gantoine <3247106+gantoine@users.noreply.github.com>
This commit is contained in:
copilot-swe-agent[bot]
2026-03-12 01:41:10 +00:00
parent 715f48e9aa
commit d45530cd8b
2 changed files with 40 additions and 22 deletions

View File

@@ -61,7 +61,7 @@ from handler.metadata.ss_handler import get_preferred_media_types
from logger.formatter import BLUE
from logger.formatter import highlight as hl
from logger.logger import log
from models.rom import Rom
from models.rom import Rom, RomUserStatus
from utils.database import safe_int, safe_str_to_bool
from utils.filesystem import sanitize_filename
from utils.hashing import crc32_to_hex
@@ -133,10 +133,21 @@ class RomUpdateForm(BaseModel):
url_manual: str | None = None
class RomUserData(BaseModel):
is_main_sibling: bool | None = Field(default=None, description="Whether this rom is the main sibling.")
backlogged: bool | None = Field(default=None, description="Whether this rom is in the backlog.")
now_playing: bool | None = Field(default=None, description="Whether this rom is currently being played.")
hidden: bool | None = Field(default=None, description="Whether this rom is hidden.")
rating: int | None = Field(default=None, description="User rating for this rom (0-10).")
difficulty: int | None = Field(default=None, description="User difficulty rating for this rom.")
completion: int | None = Field(default=None, description="User completion percentage for this rom.")
status: RomUserStatus | None = Field(default=None, description="User play status for this rom.")
class RomUserUpdatePayload(BaseModel):
data: dict[str, Any] = Field(default_factory=dict)
update_last_played: bool = False
remove_last_played: bool = False
data: RomUserData = Field(default_factory=RomUserData, description="Partial rom user data to update. Only provided fields will be updated.")
update_last_played: bool = Field(default=False, description="Set last played timestamp to now.")
remove_last_played: bool = Field(default=False, description="Clear the last played timestamp.")
async def parse_rom_update_form(
@@ -1482,8 +1493,6 @@ async def update_rom_user(
payload: Annotated[RomUserUpdatePayload, Body()],
) -> RomUserSchema:
"""Update rom data associated to the current user."""
rom_user_data = payload.data
rom = db_rom_handler.get_rom(id)
if not rom:
@@ -1493,22 +1502,7 @@ async def update_rom_user(
id, request.user.id
) or db_rom_handler.add_rom_user(id, request.user.id)
fields_to_update = [
"is_main_sibling",
"backlogged",
"now_playing",
"hidden",
"rating",
"difficulty",
"completion",
"status",
]
cleaned_data = {
field: rom_user_data[field]
for field in fields_to_update
if field in rom_user_data
}
cleaned_data = payload.data.model_dump(exclude_unset=True)
if payload.update_last_played:
cleaned_data.update({"last_played": datetime.now(timezone.utc)})

View File

@@ -139,6 +139,30 @@ def test_update_rom_user_props_with_data_envelope(
assert body["rating"] == 7
def test_update_rom_user_props_partial_update(
client: TestClient, access_token: str, rom: Rom
):
# Set initial values
client.put(
f"/api/roms/{rom.id}/props",
headers={"Authorization": f"Bearer {access_token}"},
json={"data": {"backlogged": True, "rating": 5, "hidden": True}},
)
# Partial update: only update rating, backlogged and hidden should remain unchanged
response = client.put(
f"/api/roms/{rom.id}/props",
headers={"Authorization": f"Bearer {access_token}"},
json={"data": {"rating": 9}},
)
assert response.status_code == status.HTTP_200_OK
body = response.json()
assert body["rating"] == 9
assert body["backlogged"] is True
assert body["hidden"] is True
def test_update_rom_user_props_last_played_flags(
client: TestClient, access_token: str, rom: Rom
):