Public Access
feat(stats): add owners endpoint to list users who own a game
This commit is contained in:
1 parent
7747bc7b8b
commit
2dba863c54
19 files changed
+478
-45
No files matched your search
@@ -46,6 +46,7 @@ class InternalAccountControllerTest extends AbstractIntegrationTest {
|
||||
void cleanUp() {
|
||||
jdbc.update("delete from deleted_user where user_id in (?, 42)", USER_ID);
|
||||
jdbc.update("delete from blocked_user where user_id in (?, 42)", USER_ID);
|
||||
jdbc.update("delete from listed_user where user_id in (?, 42)", USER_ID);
|
||||
jdbc.update("delete from account_name where user_id in (?, 42)", USER_ID);
|
||||
jdbc.update("delete from account_role_change where user_id in (?, 42)", USER_ID);
|
||||
}
|
||||
@@ -134,6 +135,16 @@ class InternalAccountControllerTest extends AbstractIntegrationTest {
|
||||
.andExpect(status().isBadRequest());
|
||||
}
|
||||
|
||||
@Test
|
||||
void stateCallWithListed_ListsTheUser() throws Exception {
|
||||
JsonNode call = ContractTokens.internalCall("applyStates");
|
||||
|
||||
send(contractRequest(call), call.path("request").toString(), ContractTokens.serviceToken())
|
||||
.andExpect(status().isNoContent());
|
||||
|
||||
assertThat(jdbc.queryForList("select user_id from listed_user where user_id = 42", Long.class)).containsExactly(42L);
|
||||
}
|
||||
|
||||
@Test
|
||||
void stateCallWithoutARoleChange_AnOldAuth_StoresTheBlockAndNoRoleChange() throws Exception {
|
||||
send(post("/internal/accounts/states"), "{\"accounts\":[{\"userId\":" + USER_ID + ",\"blocked\":true}]}",
|
||||
|
||||
@@ -18,7 +18,7 @@ class AccountCleanupRepositoryTest extends AbstractPersistenceTest {
|
||||
private static final List<String> USER_TABLES = List.of("user_game_status_change", "user_game_achievement",
|
||||
"user_game_achievement_meta", "user_game_playtime_day", "wishlist_game", "backlog_snapshot",
|
||||
"sync_change", "sync_result", "user_steam_sync", "game_merge_undo_user", "user_game", "game_link_request", "account_name", "game_import", "reward_ledger",
|
||||
"reward_equipped");
|
||||
"reward_equipped", "listed_user");
|
||||
|
||||
@Autowired
|
||||
private AccountCleanupRepository repository;
|
||||
@@ -50,6 +50,7 @@ class AccountCleanupRepositoryTest extends AbstractPersistenceTest {
|
||||
jdbc.update("insert into game_merge_undo_user (merge_id, user_id, combined) values (1, ?, false)", userId);
|
||||
jdbc.update("insert into game_link_request (user_id, appid_a, appid_b) values (?, 220, 620)", userId);
|
||||
jdbc.update("insert into account_name (user_id, display_name) values (?, 'lobo')", userId);
|
||||
jdbc.update("insert into listed_user (user_id) values (?)", userId);
|
||||
jdbc.update("insert into game_import (user_id, source, status, total) values (?, 'TEXT', 'SAVED', 0)", userId);
|
||||
jdbc.update("insert into reward_ledger (user_id, kind, ref, points, event_at) values (?, 'STARTER', 'STARTER', 20, now())", userId);
|
||||
jdbc.update("insert into reward_equipped (user_id, slot, item_code) values (?, 'BADGE', 'BADGE_PILE_SLAYER')", userId);
|
||||
|
||||
@@ -31,6 +31,7 @@ class AccountStateRepositoryTest extends AbstractPersistenceTest {
|
||||
@BeforeEach
|
||||
void seed() {
|
||||
jdbc.update("delete from blocked_user");
|
||||
jdbc.update("delete from listed_user");
|
||||
jdbc.update("delete from account_name");
|
||||
jdbc.update("delete from account_role_change");
|
||||
for (long userId : List.of(1L, 2L)) {
|
||||
@@ -50,24 +51,24 @@ class AccountStateRepositoryTest extends AbstractPersistenceTest {
|
||||
|
||||
@Test
|
||||
void displayName_IsStoredAndReplacedAndAStateWithoutOneKeepsIt() {
|
||||
repository.apply(new AccountState(1L, OLD_STEAM_ID, "lobo", false, null));
|
||||
repository.apply(new AccountState(1L, OLD_STEAM_ID, null, false, null));
|
||||
repository.apply(new AccountState(1L, OLD_STEAM_ID, "lobo", false, null, null));
|
||||
repository.apply(new AccountState(1L, OLD_STEAM_ID, null, false, null, null));
|
||||
assertThat(jdbc.queryForObject("select display_name from account_name where user_id = 1", String.class)).isEqualTo("lobo");
|
||||
|
||||
repository.apply(new AccountState(1L, OLD_STEAM_ID, "wolf", false, null));
|
||||
repository.apply(new AccountState(1L, OLD_STEAM_ID, "wolf", false, null, null));
|
||||
|
||||
assertThat(jdbc.queryForList("select display_name from account_name", String.class)).containsExactly("wolf");
|
||||
}
|
||||
|
||||
@Test
|
||||
void block_StopsTheNightlySyncAndUnblockLiftsTheMarker() {
|
||||
repository.apply(new AccountState(1L, OLD_STEAM_ID, null, true, null));
|
||||
repository.apply(new AccountState(1L, OLD_STEAM_ID, null, true, null, null));
|
||||
|
||||
assertThat(blocked()).containsExactly(1L);
|
||||
assertThat(sync(1L).get("user_seen_at")).isNull();
|
||||
assertThat(sync(2L).get("user_seen_at")).isNotNull();
|
||||
|
||||
repository.apply(new AccountState(1L, OLD_STEAM_ID, null, false, null));
|
||||
repository.apply(new AccountState(1L, OLD_STEAM_ID, null, false, null, null));
|
||||
|
||||
assertThat(blocked()).isEmpty();
|
||||
}
|
||||
@@ -75,7 +76,7 @@ class AccountStateRepositoryTest extends AbstractPersistenceTest {
|
||||
// steam_id stays: the next sync with the new ID compares with it and drops the old account's games.
|
||||
@Test
|
||||
void newSteamId_StopsTheNightlySyncOfTheOldIdAndSyncsOnTheNextVisit() {
|
||||
repository.apply(new AccountState(1L, NEW_STEAM_ID, null, false, null));
|
||||
repository.apply(new AccountState(1L, NEW_STEAM_ID, null, false, null, null));
|
||||
|
||||
assertThat(sync(1L).get("steam_id")).isEqualTo(String.valueOf(OLD_STEAM_ID));
|
||||
assertThat(sync(1L).get("last_synced_at")).isNull();
|
||||
@@ -84,14 +85,14 @@ class AccountStateRepositoryTest extends AbstractPersistenceTest {
|
||||
|
||||
@Test
|
||||
void sameSteamId_KeepsTheLastSync() {
|
||||
repository.apply(new AccountState(1L, OLD_STEAM_ID, null, false, null));
|
||||
repository.apply(new AccountState(1L, OLD_STEAM_ID, null, false, null, null));
|
||||
|
||||
assertThat(sync(1L).get("last_synced_at")).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void noSteamId_StopsTheNightlySync() {
|
||||
repository.apply(new AccountState(1L, null, null, false, null));
|
||||
repository.apply(new AccountState(1L, null, null, false, null, null));
|
||||
|
||||
assertThat(sync(1L).get("user_seen_at")).isNull();
|
||||
assertThat(sync(1L).get("steam_id")).isEqualTo(String.valueOf(OLD_STEAM_ID));
|
||||
@@ -99,7 +100,7 @@ class AccountStateRepositoryTest extends AbstractPersistenceTest {
|
||||
|
||||
@Test
|
||||
void userWithoutASyncRow_GetsOnlyTheBlock() {
|
||||
repository.apply(new AccountState(3L, NEW_STEAM_ID, null, true, null));
|
||||
repository.apply(new AccountState(3L, NEW_STEAM_ID, null, true, null, null));
|
||||
|
||||
assertThat(blocked()).containsExactly(3L);
|
||||
assertThat(jdbc.queryForList("select user_id from user_steam_sync where user_id = 3", Long.class)).isEmpty();
|
||||
@@ -107,10 +108,10 @@ class AccountStateRepositoryTest extends AbstractPersistenceTest {
|
||||
|
||||
@Test
|
||||
void replaceAll_LiftsTheBlocksAuthNoLongerSends() {
|
||||
repository.apply(new AccountState(1L, OLD_STEAM_ID, null, true, null));
|
||||
repository.apply(new AccountState(2L, OLD_STEAM_ID, null, true, null));
|
||||
repository.apply(new AccountState(1L, OLD_STEAM_ID, null, true, null, null));
|
||||
repository.apply(new AccountState(2L, OLD_STEAM_ID, null, true, null, null));
|
||||
|
||||
repository.replaceAll(List.of(new AccountState(2L, OLD_STEAM_ID, null, true, null)));
|
||||
repository.replaceAll(List.of(new AccountState(2L, OLD_STEAM_ID, null, true, null, null)));
|
||||
assertThat(blocked()).containsExactly(2L);
|
||||
|
||||
repository.replaceAll(List.of());
|
||||
@@ -127,13 +128,13 @@ class AccountStateRepositoryTest extends AbstractPersistenceTest {
|
||||
Instant first = Instant.parse("2026-10-04T12:00:00Z");
|
||||
Instant second = first.plusSeconds(60);
|
||||
|
||||
repository.apply(new AccountState(1L, OLD_STEAM_ID, null, false, first));
|
||||
repository.apply(new AccountState(1L, OLD_STEAM_ID, null, false, first, null));
|
||||
assertThat(changedAt(1L)).isEqualTo(first);
|
||||
|
||||
repository.apply(new AccountState(1L, OLD_STEAM_ID, null, false, null));
|
||||
repository.apply(new AccountState(1L, OLD_STEAM_ID, null, false, null, null));
|
||||
assertThat(changedAt(1L)).isEqualTo(first);
|
||||
|
||||
repository.apply(new AccountState(1L, OLD_STEAM_ID, null, false, second));
|
||||
repository.apply(new AccountState(1L, OLD_STEAM_ID, null, false, second, null));
|
||||
assertThat(changedAt(1L)).isEqualTo(second);
|
||||
}
|
||||
|
||||
@@ -142,8 +143,8 @@ class AccountStateRepositoryTest extends AbstractPersistenceTest {
|
||||
Instant first = Instant.parse("2026-10-04T12:00:01Z");
|
||||
Instant second = first.plusSeconds(1);
|
||||
|
||||
repository.apply(new AccountState(1L, OLD_STEAM_ID, null, false, second));
|
||||
repository.apply(new AccountState(1L, OLD_STEAM_ID, null, false, first));
|
||||
repository.apply(new AccountState(1L, OLD_STEAM_ID, null, false, second, null));
|
||||
repository.apply(new AccountState(1L, OLD_STEAM_ID, null, false, first, null));
|
||||
|
||||
assertThat(changedAt(1L)).isEqualTo(second);
|
||||
}
|
||||
@@ -151,11 +152,47 @@ class AccountStateRepositoryTest extends AbstractPersistenceTest {
|
||||
@Test
|
||||
void findLoginState_ReadsTheBlockAndTheRoleChange() {
|
||||
Instant change = Instant.parse("2026-10-04T12:00:00Z");
|
||||
repository.apply(new AccountState(1L, OLD_STEAM_ID, null, true, change));
|
||||
repository.apply(new AccountState(2L, OLD_STEAM_ID, null, false, null));
|
||||
repository.apply(new AccountState(1L, OLD_STEAM_ID, null, true, change, null));
|
||||
repository.apply(new AccountState(2L, OLD_STEAM_ID, null, false, null, null));
|
||||
|
||||
assertThat(repository.findLoginState(1L)).isEqualTo(new LoginState(true, change));
|
||||
assertThat(repository.findLoginState(2L)).isEqualTo(LoginState.NONE);
|
||||
assertThat(repository.findLoginState(99L)).isEqualTo(LoginState.NONE);
|
||||
}
|
||||
|
||||
private List<Long> listed() {
|
||||
return jdbc.queryForList("select user_id from listed_user order by user_id", Long.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void listed_TrueInsertsFalseDeletesNullKeeps() {
|
||||
repository.apply(new AccountState(1L, OLD_STEAM_ID, null, false, null, true));
|
||||
repository.apply(new AccountState(1L, OLD_STEAM_ID, null, false, null, null));
|
||||
assertThat(listed()).containsExactly(1L);
|
||||
|
||||
repository.apply(new AccountState(1L, OLD_STEAM_ID, null, false, null, false));
|
||||
assertThat(listed()).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
void replaceAll_ListsExactlyTheListedUsers() {
|
||||
repository.apply(new AccountState(1L, OLD_STEAM_ID, null, false, null, true));
|
||||
repository.apply(new AccountState(2L, OLD_STEAM_ID, null, false, null, true));
|
||||
|
||||
repository.replaceAll(List.of(new AccountState(2L, OLD_STEAM_ID, null, false, null, true),
|
||||
new AccountState(3L, OLD_STEAM_ID, null, false, null, false)));
|
||||
assertThat(listed()).containsExactly(2L);
|
||||
|
||||
repository.replaceAll(List.of(new AccountState(2L, OLD_STEAM_ID, null, false, null, false)));
|
||||
assertThat(listed()).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
void replaceAll_WithAStateWithoutListing_KeepsTheListing() {
|
||||
repository.apply(new AccountState(1L, OLD_STEAM_ID, null, false, null, true));
|
||||
|
||||
repository.replaceAll(List.of(new AccountState(2L, OLD_STEAM_ID, null, false, null, null)));
|
||||
|
||||
assertThat(listed()).containsExactly(1L);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
package core_service.modules.stats.api;
|
||||
|
||||
import core_service.modules.library.domain.SteamGame;
|
||||
import core_service.modules.library.domain.UserGame;
|
||||
import core_service.modules.library.repo.SteamGameRepository;
|
||||
import core_service.modules.library.repo.UserGameRepository;
|
||||
import core_service.shared.test.AbstractIntegrationTest;
|
||||
import core_service.shared.test.ContractTokens;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.webmvc.test.autoconfigure.AutoConfigureMockMvc;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.test.context.ActiveProfiles;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import tools.jackson.databind.JsonNode;
|
||||
import tools.jackson.databind.json.JsonMapper;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
/**
|
||||
* The real (non-dev) filter chain, so the login requirement is the production one.
|
||||
*/
|
||||
@AutoConfigureMockMvc
|
||||
@ActiveProfiles(value = "prod", inheritProfiles = false)
|
||||
class OwnerListControllerTest extends AbstractIntegrationTest {
|
||||
|
||||
private static final long VIEWER = 1L;
|
||||
private static final long SECRET = 2L;
|
||||
private static final long LOBO = 3L;
|
||||
private static final long BLOCKED = 4L;
|
||||
private static final long DELETED = 5L;
|
||||
|
||||
@Autowired
|
||||
private MockMvc mockMvc;
|
||||
|
||||
@Autowired
|
||||
private JdbcTemplate jdbc;
|
||||
|
||||
@Autowired
|
||||
private SteamGameRepository steamGameRepository;
|
||||
|
||||
@Autowired
|
||||
private UserGameRepository userGameRepository;
|
||||
|
||||
@BeforeEach
|
||||
void seed() {
|
||||
cleanUp();
|
||||
steamGameRepository.saveAllAndFlush(List.of(new SteamGame(220L, "Half-Life 2", null, Instant.now())));
|
||||
for (long userId : List.of(SECRET, LOBO, BLOCKED, DELETED)) {
|
||||
userGameRepository.saveAndFlush(new UserGame(userId, 220L, 100, Instant.now(), Instant.now()));
|
||||
}
|
||||
name(SECRET, "SecretTwo");
|
||||
name(LOBO, "Lobo");
|
||||
name(BLOCKED, "BlockedFour");
|
||||
name(DELETED, "DeletedFive");
|
||||
jdbc.update("insert into listed_user (user_id) values (?), (?), (?)", LOBO, BLOCKED, DELETED);
|
||||
jdbc.update("insert into blocked_user (user_id) values (?)", BLOCKED);
|
||||
jdbc.update("insert into deleted_user (user_id) values (?)", DELETED);
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void cleanUp() {
|
||||
userGameRepository.deleteAll();
|
||||
jdbc.update("delete from listed_user");
|
||||
jdbc.update("delete from account_name");
|
||||
jdbc.update("delete from blocked_user");
|
||||
jdbc.update("delete from deleted_user");
|
||||
}
|
||||
|
||||
private void name(long userId, String displayName) {
|
||||
jdbc.update("insert into account_name (user_id, display_name) values (?, ?)", userId, displayName);
|
||||
}
|
||||
|
||||
private String owners(String... params) throws Exception {
|
||||
var request = get("/api/stats/owners").header("Authorization", "Bearer " + ContractTokens.loginToken(VIEWER));
|
||||
for (int i = 0; i < params.length; i += 2) {
|
||||
request.param(params[i], params[i + 1]);
|
||||
}
|
||||
return mockMvc.perform(request).andExpect(status().isOk()).andReturn().getResponse().getContentAsString();
|
||||
}
|
||||
|
||||
@Test
|
||||
void withoutLogin_Is401() throws Exception {
|
||||
mockMvc.perform(get("/api/stats/owners").param("appid", "220")).andExpect(status().isUnauthorized());
|
||||
}
|
||||
|
||||
@Test
|
||||
void privateUser_NeverLeaksByNameOrIdAndOnlyCounts() throws Exception {
|
||||
String body = owners("appid", "220");
|
||||
JsonNode json = JsonMapper.builder().build().readTree(body);
|
||||
|
||||
assertThat(body).doesNotContain("SecretTwo", "BlockedFour", "DeletedFive");
|
||||
assertThat(json.get("listed")).hasSize(1);
|
||||
Set<String> keys = new HashSet<>();
|
||||
json.get("listed").get(0).propertyNames().forEach(keys::add);
|
||||
assertThat(keys).containsExactly("displayName");
|
||||
assertThat(json.get("listed").get(0).get("displayName").asString()).isEqualTo("Lobo");
|
||||
assertThat(json.get("listedTotal").asLong()).isEqualTo(1);
|
||||
assertThat(json.get("privateCount").asLong()).isEqualTo(1);
|
||||
assertThat(json.get("includesYou").asBoolean()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
void viewerWhoOwnsTheGameAndIsListed_IsOnlyIncludesYou() throws Exception {
|
||||
userGameRepository.saveAndFlush(new UserGame(VIEWER, 220L, 100, Instant.now(), Instant.now()));
|
||||
name(VIEWER, "Viewer");
|
||||
jdbc.update("insert into listed_user (user_id) values (?)", VIEWER);
|
||||
|
||||
String body = owners("appid", "220");
|
||||
|
||||
assertThat(body).doesNotContain("Viewer");
|
||||
mockMvc.perform(get("/api/stats/owners").param("appid", "220")
|
||||
.header("Authorization", "Bearer " + ContractTokens.loginToken(VIEWER)))
|
||||
.andExpect(jsonPath("$.includesYou").value(true))
|
||||
.andExpect(jsonPath("$.listedTotal").value(1))
|
||||
.andExpect(jsonPath("$.privateCount").value(1));
|
||||
}
|
||||
|
||||
@Test
|
||||
void badArg_Is400() throws Exception {
|
||||
mockMvc.perform(get("/api/stats/owners").param("appid", "220").param("key", "GENRE")
|
||||
.header("Authorization", "Bearer " + ContractTokens.loginToken(VIEWER)))
|
||||
.andExpect(status().isBadRequest())
|
||||
.andExpect(jsonPath("$.code").value("BAD_ARG"));
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,7 @@ import core_service.modules.library.repo.SteamGameRepository;
|
||||
import core_service.modules.library.repo.UserGameRepository;
|
||||
import core_service.modules.stats.api.dto.PublicStatsDto;
|
||||
import core_service.modules.stats.domain.CommunityKey;
|
||||
import core_service.modules.stats.domain.PeopleCounts;
|
||||
import core_service.modules.stats.service.PublicStatsService;
|
||||
import core_service.shared.test.AbstractPersistenceTest;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
@@ -251,4 +252,79 @@ class StatsRepositoryTest extends AbstractPersistenceTest {
|
||||
|
||||
assertEquals(1, statsRepository.biggestBacklog());
|
||||
}
|
||||
|
||||
private void owner(long userId, long appid, String name, boolean listed) {
|
||||
userGameRepository.saveAndFlush(new UserGame(userId, appid, 10, Instant.now(), Instant.now()));
|
||||
if (name != null) {
|
||||
jdbc.update("insert into account_name (user_id, display_name) values (?, ?)", userId, name);
|
||||
}
|
||||
if (listed) {
|
||||
jdbc.update("insert into listed_user (user_id) values (?)", userId);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void countOwners_CountsHiddenGameOwnersAsNoOwnersAndListedWithoutNameAsPrivate() {
|
||||
owner(10L, 220L, "Ann", true);
|
||||
owner(11L, 220L, null, true);
|
||||
owner(12L, 220L, "Bob", false);
|
||||
|
||||
PeopleCounts counts = statsRepository.countOwners(CommunityKey.OWNED, "", "Europe/Berlin", 220L, 99L);
|
||||
|
||||
// user 1 (seeded) + 10 + 11 + 12; user 2 owns only the hidden game 1000
|
||||
assertEquals(4, counts.others());
|
||||
assertEquals(1, counts.listed());
|
||||
assertFalse(counts.includesYou());
|
||||
assertEquals(0, statsRepository.countOwners(CommunityKey.OWNED, "", "Europe/Berlin", 1000L, 99L).others());
|
||||
}
|
||||
|
||||
@Test
|
||||
void countOwners_ViewerIsOutOfTheCountsAndFlagged() {
|
||||
owner(10L, 220L, "Ann", true);
|
||||
|
||||
PeopleCounts counts = statsRepository.countOwners(CommunityKey.OWNED, "", "Europe/Berlin", 220L, 10L);
|
||||
|
||||
assertEquals(1, counts.others());
|
||||
assertEquals(0, counts.listed());
|
||||
assertEquals(true, counts.includesYou());
|
||||
}
|
||||
|
||||
@Test
|
||||
void keptAppid_ResolvesAnOldAppidThroughTheAlias() {
|
||||
steamGameRepository.saveAllAndFlush(List.of(new SteamGame(-5L, "Old", null, Instant.now())));
|
||||
jdbc.update("insert into game_alias (from_appid, to_appid) values (-5, 220)");
|
||||
|
||||
assertEquals(220L, statsRepository.keptAppid(-5L));
|
||||
assertEquals(220L, statsRepository.keptAppid(220L));
|
||||
}
|
||||
|
||||
@Test
|
||||
void owners_MatchTheLibrariesOfTheCommunityRow() {
|
||||
owner(10L, 220L, "Ann", true);
|
||||
jdbc.update("UPDATE user_game SET status = 'FINISHED', finished_at_estimate = now() WHERE user_id = 10");
|
||||
for (CommunityKey key : List.of(CommunityKey.OWNED, CommunityKey.FINISHED_YEAR)) {
|
||||
Object arg = key == CommunityKey.OWNED ? "" : LocalDate.now().getYear();
|
||||
long libraries = ((Number) statsRepository.communityGames(key, arg, "Europe/Berlin", 0, 100).stream()
|
||||
.filter(row -> ((Number) row.get("appid")).longValue() == 220L).findFirst().orElseThrow()
|
||||
.get("libraries")).longValue();
|
||||
|
||||
PeopleCounts counts = statsRepository.countOwners(key, arg, "Europe/Berlin", 220L, 1L);
|
||||
|
||||
assertEquals(libraries, counts.others() + (counts.includesYou() ? 1 : 0), key.name());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void listedOwnerNames_PagesSortedByName() {
|
||||
for (int i = 0; i < 41; i++) {
|
||||
owner(100L + i, 220L, String.format("user%02d", 40 - i), true);
|
||||
}
|
||||
|
||||
List<String> first = statsRepository.listedOwnerNames(CommunityKey.OWNED, "", "Europe/Berlin", 220L, 99L, 0, 40);
|
||||
List<String> second = statsRepository.listedOwnerNames(CommunityKey.OWNED, "", "Europe/Berlin", 220L, 99L, 40, 40);
|
||||
|
||||
assertEquals("user00", first.get(0));
|
||||
assertEquals(40, first.size());
|
||||
assertEquals(List.of("user40"), second);
|
||||
}
|
||||
}
|
||||
@@ -37,12 +37,12 @@
|
||||
"applyStates": {
|
||||
"method": "POST",
|
||||
"path": "/internal/accounts/states",
|
||||
"request": {"accounts": [{"userId": 42, "steamId": 76561198000000001, "displayName": "lobo", "blocked": true, "roleChangedAt": "2026-10-04T12:00:00Z"}]}
|
||||
"request": {"accounts": [{"userId": 42, "steamId": 76561198000000001, "displayName": "lobo", "blocked": true, "roleChangedAt": "2026-10-04T12:00:00Z", "listed": true}]}
|
||||
},
|
||||
"replaceStates": {
|
||||
"method": "PUT",
|
||||
"path": "/internal/accounts/states",
|
||||
"request": {"accounts": [{"userId": 42, "steamId": null, "displayName": "lobo", "blocked": false, "roleChangedAt": null}]}
|
||||
"request": {"accounts": [{"userId": 42, "steamId": null, "displayName": "lobo", "blocked": false, "roleChangedAt": null, "listed": false}]}
|
||||
},
|
||||
"purge": {
|
||||
"method": "POST",
|
||||
|
||||
Reference in new issue
Block a user