diff --git a/src/main/java/com/faforever/client/player/PlayerInfoWindowController.java b/src/main/java/com/faforever/client/player/PlayerInfoWindowController.java index 8ddf81bd80..ea89a621bd 100644 --- a/src/main/java/com/faforever/client/player/PlayerInfoWindowController.java +++ b/src/main/java/com/faforever/client/player/PlayerInfoWindowController.java @@ -179,7 +179,7 @@ protected void onInitialize() { timePeriodComboBox.setConverter(timePeriodStringConverter()); timePeriodComboBox.getItems().addAll(TimePeriod.values()); - timePeriodComboBox.setValue(TimePeriod.ALL_TIME); + timePeriodComboBox.setValue(TimePeriod.LAST_MONTH); ratingTypeComboBox.setConverter(leaderboardStringConverter()); @@ -472,7 +472,11 @@ public void onRatingTypeChange() { } private Mono loadStatistics(Leaderboard leaderboard) { - return statisticsService.getRatingHistory(player, leaderboard) + TimePeriod timePeriod = timePeriodComboBox.getValue() != null ? timePeriodComboBox.getValue() : TimePeriod.ALL_TIME; + OffsetDateTime since = timePeriod == TimePeriod.ALL_TIME + ? null + : OffsetDateTime.of(timePeriod.getDate(), ZoneOffset.UTC); + return statisticsService.getRatingHistory(player, leaderboard, since) .collectList() .doOnNext(ratingHistory -> ratingData = ratingHistory) .doOnError(throwable -> { diff --git a/src/main/java/com/faforever/client/stats/StatisticsService.java b/src/main/java/com/faforever/client/stats/StatisticsService.java index 9d6127b2a3..c2873bc880 100644 --- a/src/main/java/com/faforever/client/stats/StatisticsService.java +++ b/src/main/java/com/faforever/client/stats/StatisticsService.java @@ -8,12 +8,15 @@ import com.faforever.client.mapstruct.LeaderboardMapper; import com.faforever.commons.api.elide.ElideNavigator; import com.faforever.commons.api.elide.ElideNavigatorOnCollection; +import jakarta.annotation.Nullable; import lombok.RequiredArgsConstructor; import org.springframework.cache.annotation.Cacheable; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import reactor.core.publisher.Flux; +import java.time.OffsetDateTime; + import static com.faforever.commons.api.elide.ElideNavigator.qBuilder; @@ -26,18 +29,33 @@ public class StatisticsService { private final LeaderboardMapper leaderboardMapper; @Cacheable(value = CacheNames.RATING_HISTORY, sync = true) - public Flux getRatingHistory(PlayerInfo player, Leaderboard leaderboard) { + public Flux getRatingHistory(PlayerInfo player, Leaderboard leaderboard, + @Nullable OffsetDateTime since) { ElideNavigatorOnCollection navigator = ElideNavigator.of( com.faforever.commons.api.dto.LeaderboardRatingJournal.class) .collection() .setFilter( - qBuilder().intNum( - "gamePlayerStats.player.id") - .eq(player.getId()) - .and() - .intNum( - "leaderboard.id") - .eq(leaderboard.id())) + since != null + ? qBuilder().instant( + "gamePlayerStats.scoreTime") + .after( + since.toInstant(), + false) + .and() + .intNum( + "gamePlayerStats.player.id") + .eq(player.getId()) + .and() + .intNum( + "leaderboard.id") + .eq(leaderboard.id()) + : qBuilder().intNum( + "gamePlayerStats.player.id") + .eq(player.getId()) + .and() + .intNum( + "leaderboard.id") + .eq(leaderboard.id())) .pageSize( fafApiAccessor.getMaxPageSize()); return fafApiAccessor.getAll(navigator).map(leaderboardMapper::map).cache(); diff --git a/src/main/resources/theme/user_info_window.fxml b/src/main/resources/theme/user_info_window.fxml index 50127a7cf1..8ace3d6abb 100644 --- a/src/main/resources/theme/user_info_window.fxml +++ b/src/main/resources/theme/user_info_window.fxml @@ -57,7 +57,7 @@ - + diff --git a/src/test/java/com/faforever/client/player/PlayerInfoWindowControllerTest.java b/src/test/java/com/faforever/client/player/PlayerInfoWindowControllerTest.java index 901dc70f4c..591348c1ad 100644 --- a/src/test/java/com/faforever/client/player/PlayerInfoWindowControllerTest.java +++ b/src/test/java/com/faforever/client/player/PlayerInfoWindowControllerTest.java @@ -32,6 +32,8 @@ import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; +import java.util.Objects; + import static org.instancio.Select.field; import static org.instancio.Select.scope; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -39,7 +41,10 @@ import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.ArgumentMatchers.isNull; +import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.lenient; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -97,7 +102,7 @@ public void setUp() throws Exception { lenient().when(leaderboardService.getLeaderboards()).thenReturn(Flux.just(leaderboard)); lenient().when(leaderboardService.getEntriesForPlayer(eq(player))) .thenReturn(Flux.just(Instancio.create(LeaderboardEntry.class))); - lenient().when(statisticsService.getRatingHistory(eq(player), any())) + lenient().when(statisticsService.getRatingHistory(eq(player), any(), any())) .thenReturn(Flux.fromIterable(Instancio.ofList(LeaderboardRatingJournal.class) .size(2) .set(field(LeaderboardRatingJournal::meanBefore), 1500d) @@ -183,6 +188,26 @@ public void testOnRatingTypeChange() { testSetPlayerInfoBean(); instance.ratingTypeComboBox.setValue(leaderboard); instance.onRatingTypeChange(); - verify(statisticsService, times(2)).getRatingHistory(player, leaderboard); + verify(statisticsService, times(2)).getRatingHistory(eq(player), eq(leaderboard), any()); + } + + @Test + public void testOnRatingTypeChangeWithLastMonthSuppliesNonNullSince() { + testSetPlayerInfoBean(); + instance.timePeriodComboBox.setValue(TimePeriod.LAST_MONTH); + instance.ratingTypeComboBox.setValue(leaderboard); + instance.onRatingTypeChange(); + waitForFxEvents(); + verify(statisticsService, atLeastOnce()).getRatingHistory(eq(player), eq(leaderboard), argThat(Objects::nonNull)); + } + + @Test + public void testOnRatingTypeChangeWithAllTimeSuppliesNullSince() { + testSetPlayerInfoBean(); + instance.timePeriodComboBox.setValue(TimePeriod.ALL_TIME); + instance.ratingTypeComboBox.setValue(leaderboard); + instance.onRatingTypeChange(); + waitForFxEvents(); + verify(statisticsService, atLeastOnce()).getRatingHistory(eq(player), eq(leaderboard), isNull()); } } diff --git a/src/test/java/com/faforever/client/stats/StatisticsServiceTest.java b/src/test/java/com/faforever/client/stats/StatisticsServiceTest.java index 5912819a30..89974db453 100644 --- a/src/test/java/com/faforever/client/stats/StatisticsServiceTest.java +++ b/src/test/java/com/faforever/client/stats/StatisticsServiceTest.java @@ -20,6 +20,8 @@ import reactor.core.publisher.Flux; import reactor.test.StepVerifier; +import java.time.OffsetDateTime; + import static com.faforever.commons.api.elide.ElideNavigator.qBuilder; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.argThat; @@ -50,7 +52,7 @@ public void testGetStatisticsForPlayer() throws Exception { PlayerInfo player = PlayerInfoBuilder.create().defaultValues().username("junit").get(); Flux resultFlux = Flux.just(leaderboardMapper.map(leaderboardRatingJournal)); when(fafApiAccessor.getAll(any())).thenReturn(resultFlux); - StepVerifier.create(instance.getRatingHistory(player, leaderboard)).expectNextCount(1) + StepVerifier.create(instance.getRatingHistory(player, leaderboard, null)).expectNextCount(1) .expectComplete() .verify(); verify(fafApiAccessor).getAll(argThat( @@ -60,4 +62,27 @@ public void testGetStatisticsForPlayer() throws Exception { )); verify(fafApiAccessor).getAll(argThat(ElideMatchers.hasPageSize(10000))); } + + @Test + public void testGetStatisticsForPlayerWithSince() throws Exception { + LeaderboardRatingJournal leaderboardRatingJournal = Instancio.create(LeaderboardRatingJournal.class); + PlayerInfo player = PlayerInfoBuilder.create().defaultValues().username("junit").get(); + OffsetDateTime since = OffsetDateTime.now().minusDays(1); + Flux resultFlux = Flux.just(leaderboardMapper.map(leaderboardRatingJournal)); + when(fafApiAccessor.getAll(any())).thenReturn(resultFlux); + StepVerifier.create(instance.getRatingHistory(player, leaderboard, since)).expectNextCount(1) + .expectComplete() + .verify(); + verify(fafApiAccessor).getAll(argThat( + ElideMatchers.hasFilter(qBuilder().instant("gamePlayerStats.scoreTime") + .after(since.toInstant(), false) + .and() + .intNum("gamePlayerStats.player.id") + .eq(player.getId()) + .and() + .intNum("leaderboard.id") + .eq(leaderboard.id())) + )); + verify(fafApiAccessor).getAll(argThat(ElideMatchers.hasPageSize(10000))); + } }