diff --git a/backend/endpoints/rom.py b/backend/endpoints/rom.py index 5121eb469..0311ccc1b 100644 --- a/backend/endpoints/rom.py +++ b/backend/endpoints/rom.py @@ -233,6 +233,12 @@ def get_roms( bool | None, Query(description="Whether the rom is marked as duplicate."), ] = None, + last_played: Annotated[ + bool | None, + Query( + description="Whether the rom has a last played value for the current user." + ), + ] = None, playable: Annotated[ bool | None, Query(description="Whether the rom is playable from the browser."), @@ -404,6 +410,7 @@ def get_roms( matched=matched, favorite=favorite, duplicate=duplicate, + last_played=last_played, playable=playable, has_ra=has_ra, missing=missing, diff --git a/backend/handler/database/roms_handler.py b/backend/handler/database/roms_handler.py index 6ec943e00..e465f5ce2 100644 --- a/backend/handler/database/roms_handler.py +++ b/backend/handler/database/roms_handler.py @@ -311,6 +311,18 @@ class DBRomsHandler(DBBaseHandler): predicate = not_(predicate) return query.join(Platform).filter(predicate) + def filter_by_last_played( + self, query: Query, value: bool, user_id: int | None = None + ) -> Query: + """Filter based on whether the rom has a last played value for the user.""" + if not user_id: + return query + + predicate = RomUser.last_played.isnot(None) + if not value: + predicate = RomUser.last_played.is_(None) + return query.filter(predicate) + def filter_by_has_ra(self, query: Query, value: bool) -> Query: predicate = Rom.ra_id.isnot(None) if not value: @@ -457,6 +469,7 @@ class DBRomsHandler(DBBaseHandler): matched: bool | None = None, favorite: bool | None = None, duplicate: bool | None = None, + last_played: bool | None = None, playable: bool | None = None, has_ra: bool | None = None, missing: bool | None = None, @@ -515,6 +528,11 @@ class DBRomsHandler(DBBaseHandler): if duplicate is not None: query = self.filter_by_duplicate(query, value=duplicate) + if last_played is not None: + query = self.filter_by_last_played( + query, value=last_played, user_id=user_id + ) + if playable is not None: query = self.filter_by_playable(query, value=playable) @@ -730,6 +748,7 @@ class DBRomsHandler(DBBaseHandler): matched=kwargs.get("matched", None), favorite=kwargs.get("favorite", None), duplicate=kwargs.get("duplicate", None), + last_played=kwargs.get("last_played", None), playable=kwargs.get("playable", None), has_ra=kwargs.get("has_ra", None), missing=kwargs.get("missing", None), diff --git a/backend/tests/handler/test_db_handler.py b/backend/tests/handler/test_db_handler.py index e71002b01..0f373d525 100644 --- a/backend/tests/handler/test_db_handler.py +++ b/backend/tests/handler/test_db_handler.py @@ -1,3 +1,5 @@ +from datetime import datetime, timezone + from sqlalchemy.exc import IntegrityError from handler.auth import auth_handler @@ -70,6 +72,39 @@ def test_roms(rom: Rom, platform: Platform): assert len(roms) == 1 +def test_filter_last_played(rom: Rom, platform: Platform, admin_user: User): + second_rom = db_rom_handler.add_rom( + Rom( + platform_id=platform.id, + name="test_rom_unplayed", + slug="test_rom_unplayed_slug", + fs_name="test_rom_unplayed.zip", + fs_name_no_tags="test_rom_unplayed", + fs_name_no_ext="test_rom_unplayed", + fs_extension="zip", + fs_path=f"{platform.slug}/roms", + ) + ) + db_rom_handler.add_rom_user(rom_id=second_rom.id, user_id=admin_user.id) + + rom_user = db_rom_handler.get_rom_user(rom.id, admin_user.id) + assert rom_user is not None + + db_rom_handler.update_rom_user( + rom_user.id, {"last_played": datetime(2024, 1, 1, tzinfo=timezone.utc)} + ) + + played_roms = db_rom_handler.get_roms_scalar( + user_id=admin_user.id, last_played=True + ) + assert {r.id for r in played_roms} == {rom.id} + + unplayed_roms = db_rom_handler.get_roms_scalar( + user_id=admin_user.id, last_played=False + ) + assert {r.id for r in unplayed_roms} == {second_rom.id} + + def test_users(admin_user): db_user_handler.add_user( User( diff --git a/frontend/src/services/api/rom.ts b/frontend/src/services/api/rom.ts index e6c63634f..4e5618877 100644 --- a/frontend/src/services/api/rom.ts +++ b/frontend/src/services/api/rom.ts @@ -244,6 +244,7 @@ async function getRecentPlayedRoms(): Promise<{ data: GetRomsResponse }> { order_dir: "desc", limit: RECENT_PLAYED_ROMS_LIMIT, with_char_index: false, + last_played: true, }, }); } diff --git a/frontend/src/services/cache/api.ts b/frontend/src/services/cache/api.ts index f68ce171b..8138b17ed 100644 --- a/frontend/src/services/cache/api.ts +++ b/frontend/src/services/cache/api.ts @@ -152,6 +152,7 @@ class CachedApiService { order_dir: "desc", limit: 15, with_char_index: false, + last_played: true, }); return cacheService.request(config, onBackgroundUpdate); @@ -177,6 +178,7 @@ class CachedApiService { order_dir: "desc", limit: 15, with_char_index: false, + last_played: true, }); }