Public Access
feat(library): add source filter to owned games
A row matches when its own source, or the source of a listed linked edition, is selected. The hidden view ignores the filter.
This commit is contained in:
1 parent
6cd92f3e83
commit
8e4c382563
7 files changed
+186
-15
No files matched your search
@@ -213,7 +213,7 @@ ArchUnit role rules (`RoleAnnotationRules`) and `src/test/resources/contract/aut
|
||||
| `POST` | `/api/rewards/purchases` (`{item}`; `200` wallet, `409 ALREADY_OWNED` / `NOT_ENOUGH_POINTS` / `NOT_FOR_SALE`) | JWT |
|
||||
| `GET` | `/api/rewards/progress/{track}/games?page=`, `/api/rewards/history/{kind}/{ref}/games?page=` (the games behind a track or a `MONTH` / `STREAK` bonus; `400 NOT_A_GAME_LIST`) | JWT |
|
||||
| `PUT` | `/api/rewards/equipped/{slot}` (`{item}`, null = take off; `200` wallet, `409 NOT_OWNED`, `400 WRONG_SLOT`) | JWT |
|
||||
| `GET` | `/api/library/games` (`hideDuplicates=true` leaves out the lesser editions of a linked set), `/api/library/games/{appid}` | JWT |
|
||||
| `GET` | `/api/library/games` (`hideDuplicates=true` leaves out the lesser editions of a linked set; `source=STEAM,PSN` keeps rows whose own source or a listed linked edition's source is selected; ignored with `hidden=true`; `400` on an unknown source), `/api/library/games/{appid}` | JWT |
|
||||
| `PATCH` | `/api/library/games/{appid}/backlog` (only the sent fields; `null` clears one) | JWT |
|
||||
| `PUT`, `DELETE` | `/api/library/games/{appid}/corrections/{field}` (`{value}`; `name`, `image`, `speedrun`, `moods`, `endless`, `genres`, `time_to_beat` = `{normallyMinutes, completelyMinutes}`; `204`, `400 INVALID_CORRECTION`) | JWT, AUDITOR |
|
||||
| `GET` | `/api/library/catalog?q=&page=&size=` (every game some user still has, by name part, `PageDto` of `{appid, name, imageUrl, platforms}`; `q` at most 100 characters; size 20, 40 or 80) | JWT, AUDITOR |
|
||||
@@ -246,7 +246,7 @@ ArchUnit role rules (`RoleAnnotationRules`) and `src/test/resources/contract/aut
|
||||
| `GET` | `/api/library/stats?groups=` (`OVERVIEW`, `PILE`, `TOP_GAMES`, `TASTE`, `HABITS`, `FINISHED`, `TREND`, `PLATFORMS`; none = all) | JWT |
|
||||
| `GET` | `/api/library/stats/games?key=&arg=&page=` (the games behind a stats number; `400 BAD_ARG`) | JWT |
|
||||
| `GET` | `/api/library/achievements/summary` (Steam achievements and PlayStation trophies; one entry per game, platinum = perfect) | JWT |
|
||||
| `GET` | `/api/library/sync-status`, `/summary`, `/activity`, `/wishlist`, `/steam-profile`, `/games-count` (`canSync`: a Steam ID or a PlayStation link) | JWT |
|
||||
| `GET` | `/api/library/sync-status`, `/summary`, `/activity`, `/wishlist`, `/steam-profile`, `/games-count` (`canSync`: a Steam ID or a PlayStation link; `sources`: the sources of the user's games) | JWT |
|
||||
| `GET` | `/api/public/profiles/library` | profile ticket |
|
||||
| `GET` | `/api/public/profiles/library/stats/games?key=&arg=&page=` (`403 NOT_SHARED`, `400 BAD_ARG`) | profile ticket |
|
||||
| `GET` | `/api/public/profiles/rewards` (`{equipped}`, the worn looks) | profile ticket |
|
||||
|
||||
@@ -36,6 +36,7 @@ import core_service.modules.library.domain.AuditEntry;
|
||||
import core_service.modules.library.domain.CatalogGame;
|
||||
import core_service.modules.library.domain.CatalogGameDetail;
|
||||
import core_service.modules.library.domain.CatalogHit;
|
||||
import core_service.modules.library.domain.GameSource;
|
||||
import core_service.modules.library.domain.GameStatus;
|
||||
import core_service.modules.library.domain.LinkPair;
|
||||
import core_service.modules.library.domain.Mood;
|
||||
@@ -121,7 +122,8 @@ public class LibraryController {
|
||||
boolean syncStarted = syncService.syncIfStale(userId, steamId);
|
||||
long count = queryService.countOwnedGames(userId);
|
||||
return ResponseEntity.ok(Map.of("count", count, "hasSteamId", principal.steamId() != null,
|
||||
"canSync", syncService.canSync(userId, steamId), "syncStarted", syncStarted));
|
||||
"canSync", syncService.canSync(userId, steamId), "syncStarted", syncStarted,
|
||||
"sources", queryService.listSources(userId)));
|
||||
}
|
||||
|
||||
@GetMapping("/games")
|
||||
@@ -134,7 +136,8 @@ public class LibraryController {
|
||||
@RequestParam(required = false) String q,
|
||||
@RequestParam(required = false) Integer maxMinutes,
|
||||
@RequestParam(defaultValue = "false") boolean hidden,
|
||||
@RequestParam(defaultValue = "false") boolean hideDuplicates
|
||||
@RequestParam(defaultValue = "false") boolean hideDuplicates,
|
||||
@RequestParam(required = false) List<GameSource> source
|
||||
) {
|
||||
Long userId = principal.getIdAsLong();
|
||||
syncService.syncIfStale(userId, principal.steamIdText().orElse(null));
|
||||
@@ -142,7 +145,7 @@ public class LibraryController {
|
||||
int safeSize = ALLOWED_SIZES.contains(size) ? size : DEFAULT_SIZE;
|
||||
int safePage = Math.max(0, page);
|
||||
Sort safeSort = parseSort(sort);
|
||||
var dtoPage = queryService.listOwnedGames(userId, hidden, status, q, maxMinutes != null && maxMinutes > 0 ? maxMinutes : null, hideDuplicates, PageRequest.of(safePage, safeSize, safeSort));
|
||||
var dtoPage = queryService.listOwnedGames(userId, hidden, status, q, maxMinutes != null && maxMinutes > 0 ? maxMinutes : null, hideDuplicates, hidden ? null : source, PageRequest.of(safePage, safeSize, safeSort));
|
||||
return ResponseEntity.ok(PageDto.of(dtoPage));
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
package core_service.modules.library.domain;
|
||||
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.Table;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.hibernate.annotations.Immutable;
|
||||
|
||||
/**
|
||||
* A key in a linked set: read-only, see V28. Writes go through {@code GameLinkRepository}.
|
||||
*/
|
||||
@Entity
|
||||
@Immutable
|
||||
@Table(name = "game_link")
|
||||
@Getter
|
||||
@NoArgsConstructor(access = AccessLevel.PROTECTED)
|
||||
public class GameLinkMember {
|
||||
|
||||
@Id
|
||||
@Column(name = "appid")
|
||||
private Long appid;
|
||||
|
||||
@Column(name = "set_id")
|
||||
private Long setId;
|
||||
}
|
||||
@@ -2,6 +2,7 @@ package core_service.modules.library.repo;
|
||||
|
||||
import core_service.modules.library.domain.AchievementProgress;
|
||||
import core_service.modules.library.domain.FinishedWithoutDate;
|
||||
import core_service.modules.library.domain.GameSource;
|
||||
import core_service.modules.library.domain.GameStatus;
|
||||
import core_service.modules.library.domain.Mood;
|
||||
import core_service.modules.library.domain.StatusCount;
|
||||
@@ -320,6 +321,7 @@ public interface UserGameRepository extends JpaRepository<UserGame, UserGameId>
|
||||
* @param namePattern a {@link #containsPattern} result, null for every name
|
||||
* @param maxMinutes only games whose normal time to beat is known and at most this; null for every game
|
||||
* @param hideDuplicates only the games a linked set counts (see V28), not its lesser editions
|
||||
* @param sources the sources a row or one of its listed linked editions must have; never empty
|
||||
*/
|
||||
@Query("select ug from UserGame ug join SteamGame sg on sg.appid = ug.appid " +
|
||||
"where ug.userId = :userId and ug.removedAt is null " +
|
||||
@@ -329,15 +331,23 @@ public interface UserGameRepository extends JpaRepository<UserGame, UserGameId>
|
||||
"and (:maxMinutes is null or exists (select 1 from GameTimeToBeat t " +
|
||||
" where t.appid = ug.appid and t.normallyMinutes <= :maxMinutes)) " +
|
||||
"and (:hideDuplicates = false or exists (select 1 from CountedUserGame c " +
|
||||
" where c.userId = ug.userId and c.appid = ug.appid))")
|
||||
" where c.userId = ug.userId and c.appid = ug.appid)) " +
|
||||
"and (ug.source in :sources or exists (select 1 from GameLinkMember l " +
|
||||
" join GameLinkMember o on o.setId = l.setId and o.appid <> l.appid " +
|
||||
" join UserGame og on og.userId = ug.userId and og.appid = o.appid " +
|
||||
" where l.appid = ug.appid and og.removedAt is null and og.hiddenAt is null and og.source in :sources))")
|
||||
Page<UserGame> findOwnedGames(@Param("userId") Long userId,
|
||||
@Param("hidden") boolean hidden,
|
||||
@Param("status") GameStatus status,
|
||||
@Param("namePattern") String namePattern,
|
||||
@Param("maxMinutes") Integer maxMinutes,
|
||||
@Param("hideDuplicates") boolean hideDuplicates,
|
||||
@Param("sources") Collection<GameSource> sources,
|
||||
Pageable pageable);
|
||||
|
||||
@Query("select distinct ug.source from UserGame ug where ug.userId = :userId and ug.removedAt is null")
|
||||
List<GameSource> findSources(@Param("userId") Long userId);
|
||||
|
||||
/**
|
||||
* Normal time to beat of the user's backlog, only games IGDB has data for.
|
||||
*/
|
||||
|
||||
@@ -61,6 +61,7 @@ import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Comparator;
|
||||
import java.util.EnumMap;
|
||||
import java.util.EnumSet;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -110,12 +111,18 @@ public class LibraryQueryService {
|
||||
return userGameRepository.countListed(userId);
|
||||
}
|
||||
|
||||
public List<GameSource> listSources(Long userId) {
|
||||
return userGameRepository.findSources(userId).stream().sorted().toList();
|
||||
}
|
||||
|
||||
public Page<GameDto> listOwnedGames(Long userId, boolean hidden, GameStatus status, String nameQuery,
|
||||
Integer maxMinutes, boolean hideDuplicates, Pageable pageable) {
|
||||
Integer maxMinutes, boolean hideDuplicates, Collection<GameSource> sources,
|
||||
Pageable pageable) {
|
||||
Pageable stable = PageRequest.of(pageable.getPageNumber(), pageable.getPageSize(),
|
||||
UserGameRepository.querySort(pageable.getSort()));
|
||||
Page<UserGame> page = userGameRepository.findOwnedGames(
|
||||
userId, hidden, status, UserGameRepository.containsPattern(nameQuery), maxMinutes, hideDuplicates, stable);
|
||||
userId, hidden, status, UserGameRepository.containsPattern(nameQuery), maxMinutes, hideDuplicates,
|
||||
sources == null || sources.isEmpty() ? EnumSet.allOf(GameSource.class) : sources, stable);
|
||||
List<GameDto> games = toDtos(page.getContent());
|
||||
return new PageImpl<>(games, page.getPageable(), page.getTotalElements());
|
||||
}
|
||||
|
||||
@@ -282,4 +282,73 @@ class GameLinkFlowTest extends AbstractIntegrationTest {
|
||||
mockMvc.perform(as(get("/api/library/games"), USER_A, Role.USER)).andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.totalElements").value(2));
|
||||
}
|
||||
|
||||
private void setSource(long appid, GameSource source) {
|
||||
jdbc.update("update user_game set source = ? where user_id = ? and appid = ?", source.name(), USER_A, appid);
|
||||
}
|
||||
|
||||
private ResultActions games(String query) throws Exception {
|
||||
return mockMvc.perform(as(get("/api/library/games" + query), USER_A, Role.USER)).andExpect(status().isOk());
|
||||
}
|
||||
|
||||
@Test
|
||||
void sourceFilter_ALinkedSetMatchesByAnyListedEdition() throws Exception {
|
||||
setSource(GAME_2, GameSource.PSN);
|
||||
linkAs(Role.AUDITOR, GAME, GAME_2).andExpect(status().isNoContent());
|
||||
|
||||
games("?source=PSN").andExpect(jsonPath("$.totalElements").value(2));
|
||||
games("?source=PSN&hideDuplicates=true").andExpect(jsonPath("$.totalElements").value(1));
|
||||
games("?source=STEAM").andExpect(jsonPath("$.totalElements").value(0));
|
||||
games("?source=MANUAL,STEAM").andExpect(jsonPath("$.totalElements").value(2));
|
||||
}
|
||||
|
||||
@Test
|
||||
void sourceFilter_WithoutALinkOnlyTheOwnSourceMatches() throws Exception {
|
||||
setSource(GAME_2, GameSource.PSN);
|
||||
|
||||
games("?source=PSN").andExpect(jsonPath("$.totalElements").value(1))
|
||||
.andExpect(jsonPath("$.content[0].appid").value(GAME_2));
|
||||
}
|
||||
|
||||
@Test
|
||||
void sourceFilter_AHiddenEditionDoesNotCount() throws Exception {
|
||||
setSource(GAME_2, GameSource.PSN);
|
||||
linkAs(Role.AUDITOR, GAME, GAME_2).andExpect(status().isNoContent());
|
||||
jdbc.update("update user_game set hidden_at = now() where user_id = ? and appid = ?", USER_A, GAME_2);
|
||||
|
||||
games("?source=PSN").andExpect(jsonPath("$.totalElements").value(0));
|
||||
games("?source=MANUAL").andExpect(jsonPath("$.totalElements").value(1));
|
||||
}
|
||||
|
||||
@Test
|
||||
void sourceFilter_CombinesWithStatus() throws Exception {
|
||||
setSource(GAME_2, GameSource.PSN);
|
||||
jdbc.update("update user_game set status = 'FINISHED' where user_id = ? and appid = ?", USER_A, GAME);
|
||||
|
||||
games("?source=MANUAL&status=FINISHED").andExpect(jsonPath("$.totalElements").value(1));
|
||||
games("?source=PSN&status=FINISHED").andExpect(jsonPath("$.totalElements").value(0));
|
||||
games("?source=PSN&status=BACKLOG").andExpect(jsonPath("$.totalElements").value(1));
|
||||
}
|
||||
|
||||
@Test
|
||||
void sourceFilter_HiddenViewIgnoresIt() throws Exception {
|
||||
jdbc.update("update user_game set hidden_at = now() where user_id = ? and appid = ?", USER_A, GAME);
|
||||
|
||||
games("?hidden=true&source=PSN").andExpect(jsonPath("$.totalElements").value(1));
|
||||
}
|
||||
|
||||
@Test
|
||||
void sourceFilter_UnknownValueIs400() throws Exception {
|
||||
mockMvc.perform(as(get("/api/library/games?source=XBOX"), USER_A, Role.USER)).andExpect(status().isBadRequest());
|
||||
}
|
||||
|
||||
@Test
|
||||
void gamesCount_AnswersTheSources() throws Exception {
|
||||
setSource(GAME_2, GameSource.PSN);
|
||||
|
||||
mockMvc.perform(as(get("/api/library/games-count"), USER_A, Role.USER)).andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.sources[0]").value("MANUAL"))
|
||||
.andExpect(jsonPath("$.sources[1]").value("PSN"))
|
||||
.andExpect(jsonPath("$.sources", hasSize(2)));
|
||||
}
|
||||
}
|
||||
@@ -26,6 +26,7 @@ import org.springframework.transaction.support.TransactionTemplate;
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDate;
|
||||
import java.time.ZoneId;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
@@ -37,6 +38,7 @@ class UserGameRepositoryTest extends AbstractPersistenceTest {
|
||||
|
||||
private static final long USER_ID = 1L;
|
||||
private static final ZoneId BERLIN = ZoneId.of("Europe/Berlin");
|
||||
private static final Set<GameSource> ALL_SOURCES = EnumSet.allOf(GameSource.class);
|
||||
private static final PageRequest PAGE = PageRequest.of(0, 20, Sort.by(Sort.Direction.DESC, "playtimeMinutes"));
|
||||
|
||||
@Autowired
|
||||
@@ -79,7 +81,7 @@ class UserGameRepositoryTest extends AbstractPersistenceTest {
|
||||
}
|
||||
|
||||
private List<Long> appids(GameStatus status, String query) {
|
||||
return userGameRepository.findOwnedGames(USER_ID, false, status, UserGameRepository.containsPattern(query), null, false, PAGE)
|
||||
return userGameRepository.findOwnedGames(USER_ID, false, status, UserGameRepository.containsPattern(query), null, false, ALL_SOURCES, PAGE)
|
||||
.map(UserGame::getAppid).getContent();
|
||||
}
|
||||
|
||||
@@ -208,7 +210,7 @@ class UserGameRepositoryTest extends AbstractPersistenceTest {
|
||||
|
||||
@Test
|
||||
void findOwnedGames_CountsAllMatchesAcrossPages() {
|
||||
var page = userGameRepository.findOwnedGames(USER_ID, false, null, UserGameRepository.containsPattern("half"), null, false,
|
||||
var page = userGameRepository.findOwnedGames(USER_ID, false, null, UserGameRepository.containsPattern("half"), null, false, ALL_SOURCES,
|
||||
PageRequest.of(0, 1, Sort.by("appid")));
|
||||
|
||||
assertEquals(List.of(220L), page.map(UserGame::getAppid).getContent());
|
||||
@@ -216,7 +218,7 @@ class UserGameRepositoryTest extends AbstractPersistenceTest {
|
||||
}
|
||||
|
||||
private List<Long> sortedAppids(Sort sort) {
|
||||
return userGameRepository.findOwnedGames(USER_ID, false, null, null, null, false, PageRequest.of(0, 20, UserGameRepository.querySort(sort)))
|
||||
return userGameRepository.findOwnedGames(USER_ID, false, null, null, null, false, ALL_SOURCES, PageRequest.of(0, 20, UserGameRepository.querySort(sort)))
|
||||
.map(UserGame::getAppid).getContent();
|
||||
}
|
||||
|
||||
@@ -267,7 +269,7 @@ class UserGameRepositoryTest extends AbstractPersistenceTest {
|
||||
new GameTimeToBeat(620L, 300, 480, 900, Instant.now()),
|
||||
new GameTimeToBeat(380L, null, null, null, Instant.now())));
|
||||
|
||||
List<Long> shortGames = userGameRepository.findOwnedGames(USER_ID, false, null, null, 600, false, PAGE).map(UserGame::getAppid).getContent();
|
||||
List<Long> shortGames = userGameRepository.findOwnedGames(USER_ID, false, null, null, 600, false, ALL_SOURCES, PAGE).map(UserGame::getAppid).getContent();
|
||||
|
||||
assertEquals(List.of(620L), shortGames);
|
||||
}
|
||||
@@ -294,7 +296,7 @@ class UserGameRepositoryTest extends AbstractPersistenceTest {
|
||||
hide(620L, 700L);
|
||||
|
||||
assertEquals(List.of(220L, 380L), appids(null, null));
|
||||
assertEquals(List.of(620L, 700L), userGameRepository.findOwnedGames(USER_ID, true, null, null, null, false,
|
||||
assertEquals(List.of(620L, 700L), userGameRepository.findOwnedGames(USER_ID, true, null, null, null, false, ALL_SOURCES,
|
||||
PageRequest.of(0, 20, Sort.by("appid"))).map(UserGame::getAppid).getContent());
|
||||
assertEquals(Set.of(620L, 700L), Set.copyOf(userGameRepository.findHiddenAppids(USER_ID)));
|
||||
}
|
||||
@@ -359,6 +361,58 @@ class UserGameRepositoryTest extends AbstractPersistenceTest {
|
||||
Set.copyOf(userGameRepository.countByStatus(USER_ID)));
|
||||
}
|
||||
|
||||
private void setSource(GameSource source, long... appids) {
|
||||
entityManager.flush();
|
||||
for (long appid : appids) {
|
||||
jdbc.update("update user_game set source = ? where user_id = ? and appid = ?", source.name(), USER_ID, appid);
|
||||
}
|
||||
entityManager.clear();
|
||||
}
|
||||
|
||||
private List<Long> appidsOfSources(GameSource... sources) {
|
||||
return userGameRepository.findOwnedGames(USER_ID, false, null, null, null, false, Set.of(sources),
|
||||
PageRequest.of(0, 20, Sort.by("appid"))).map(UserGame::getAppid).getContent();
|
||||
}
|
||||
|
||||
@Test
|
||||
void findOwnedGames_BySource_OnlyRowsOfTheSource() {
|
||||
setSource(GameSource.PSN, 380L, 700L);
|
||||
|
||||
assertEquals(List.of(380L, 700L), appidsOfSources(GameSource.PSN));
|
||||
assertEquals(List.of(220L, 620L), appidsOfSources(GameSource.STEAM));
|
||||
assertEquals(List.of(), appidsOfSources(GameSource.MANUAL));
|
||||
}
|
||||
|
||||
@Test
|
||||
void findOwnedGames_BySource_SeveralSourcesMatchEither() {
|
||||
setSource(GameSource.PSN, 380L);
|
||||
setSource(GameSource.MANUAL, 700L);
|
||||
|
||||
assertEquals(List.of(220L, 380L, 620L), appidsOfSources(GameSource.STEAM, GameSource.PSN));
|
||||
assertEquals(List.of(380L, 700L), appidsOfSources(GameSource.PSN, GameSource.MANUAL));
|
||||
}
|
||||
|
||||
@Test
|
||||
void findOwnedGames_BySource_FollowsASteamTakeOver() {
|
||||
setSource(GameSource.MANUAL, 700L);
|
||||
assertEquals(List.of(700L), appidsOfSources(GameSource.MANUAL));
|
||||
|
||||
setSource(GameSource.STEAM, 700L);
|
||||
|
||||
assertEquals(List.of(), appidsOfSources(GameSource.MANUAL));
|
||||
assertEquals(List.of(220L, 380L, 620L, 700L), appidsOfSources(GameSource.STEAM));
|
||||
}
|
||||
|
||||
@Test
|
||||
void findSources_DistinctNotRemoved() {
|
||||
setSource(GameSource.PSN, 380L, 700L);
|
||||
setSource(GameSource.MANUAL, 620L);
|
||||
jdbc.update("update user_game set removed_at = now() where user_id = ? and appid = ?", USER_ID, 620L);
|
||||
|
||||
assertEquals(Set.of(GameSource.STEAM, GameSource.PSN), Set.copyOf(userGameRepository.findSources(USER_ID)));
|
||||
assertEquals(2, userGameRepository.findSources(USER_ID).size());
|
||||
}
|
||||
|
||||
private void link(long... appids) {
|
||||
jdbc.update("delete from game_link");
|
||||
for (long appid : appids) {
|
||||
@@ -374,9 +428,9 @@ class UserGameRepositoryTest extends AbstractPersistenceTest {
|
||||
assertEquals(Set.of(new StatusCount(GameStatus.PLAYING, 2), new StatusCount(GameStatus.BACKLOG, 1)),
|
||||
Set.copyOf(userGameRepository.countByStatus(USER_ID)));
|
||||
assertEquals(1, userGameRepository.countListedNeverPlayed(USER_ID));
|
||||
assertEquals(List.of(220L, 380L, 620L), userGameRepository.findOwnedGames(USER_ID, false, null, null, null, true,
|
||||
assertEquals(List.of(220L, 380L, 620L), userGameRepository.findOwnedGames(USER_ID, false, null, null, null, true, ALL_SOURCES,
|
||||
PageRequest.of(0, 20, Sort.by("appid"))).map(UserGame::getAppid).getContent());
|
||||
assertEquals(List.of(220L, 380L, 620L, 700L), userGameRepository.findOwnedGames(USER_ID, false, null, null, null, false,
|
||||
assertEquals(List.of(220L, 380L, 620L, 700L), userGameRepository.findOwnedGames(USER_ID, false, null, null, null, false, ALL_SOURCES,
|
||||
PageRequest.of(0, 20, Sort.by("appid"))).map(UserGame::getAppid).getContent());
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user