feat(settings): store chart form choice per stat group
Build, Test & Push Auth Service / quality-check (push) Successful in 1m0s
Build, Test & Push Auth Service / docker (push) Successful in 1m24s

This commit is contained in:
lobo committed 2026-10-04 10:43:02 +02:00
1 parent 19463a1a4d
commit 3410cbc598
19 files changed
+310 -8

No files matched your search

@@ -102,6 +102,23 @@ class PublicProfileControllerTest extends AbstractIntegrationTest {
.andExpect(jsonPath("$.style.tiles[1].size").value("L"));
}
@Test
void publicProfile_AnswersWithTheOwnersStatCharts() throws Exception {
jdbc.update("update user_settings set stat_charts = '{PLATFORMS:DONUT,TREND:BARS}' where user_id = ?",
publicUserId);
mockMvc.perform(get("/api/public/profiles/Lobo"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.style.statCharts.PLATFORMS").value("DONUT"))
.andExpect(jsonPath("$.style.statCharts.TREND").value("BARS"));
}
@Test
void publicProfile_NewRowHasNoStatCharts() throws Exception {
mockMvc.perform(get("/api/public/profiles/Lobo"))
.andExpect(jsonPath("$.style.statCharts").isEmpty());
}
@Test
void publicProfile_NewRowShowsTheDefaultTiles() throws Exception {
mockMvc.perform(get("/api/public/profiles/Lobo"))
@@ -36,6 +36,7 @@ import org.springframework.test.web.servlet.MockMvc;
import java.time.Instant;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import static org.hamcrest.Matchers.nullValue;
import static org.mockito.ArgumentMatchers.*;
@@ -369,7 +370,8 @@ class UserControllerTest extends AbstractWebMvcTest {
String email = "test@example.com";
UserSettings settings = UserSettings.builder().language("en").theme("dark")
.dashboardTiles(List.of(new Tile("STATS_TREND", "L")))
.profileTiles(List.of(new Tile("PLAYING", "S"))).favoritePlatform("PS5").build();
.profileTiles(List.of(new Tile("PLAYING", "S"))).favoritePlatform("PS5")
.statCharts(Map.of("PLATFORMS", "PIE")).build();
SecurityContextHolder.getContext().setAuthentication(
new UsernamePasswordAuthenticationToken(new UserPrincipal("1", null), null, Collections.emptyList())
);
@@ -381,7 +383,8 @@ class UserControllerTest extends AbstractWebMvcTest {
.andExpect(jsonPath("$.settings.dashboardTiles[0].size").value("L"))
.andExpect(jsonPath("$.settings.profileTiles[0].id").value("PLAYING"))
.andExpect(jsonPath("$.settings.profileTiles[0].size").value("S"))
.andExpect(jsonPath("$.settings.favoritePlatform").value("PS5"));
.andExpect(jsonPath("$.settings.favoritePlatform").value("PS5"))
.andExpect(jsonPath("$.settings.statCharts.PLATFORMS").value("PIE"));
}
@Test
@@ -459,6 +462,47 @@ class UserControllerTest extends AbstractWebMvcTest {
verify(userService).updateDashboardTiles(1L, null);
}
@Test
void updateStatChart_StoresOrClearsTheChoice() throws Exception {
SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken(
new UserPrincipal("1", null), null, Collections.emptyList()));
mockMvc.perform(put("/api/users/settings/stat-chart")
.contentType(MediaType.APPLICATION_JSON)
.content("{\"group\":\"PLATFORMS\",\"chart\":\"PIE\"}"))
.andExpect(status().isNoContent());
mockMvc.perform(put("/api/users/settings/stat-chart")
.contentType(MediaType.APPLICATION_JSON)
.content("{\"group\":\"FINISHED\",\"chart\":null}"))
.andExpect(status().isNoContent());
verify(userService).updateStatChart(1L, "PLATFORMS", "PIE");
verify(userService).updateStatChart(1L, "FINISHED", null);
}
@ParameterizedTest
@ValueSource(strings = {
"{\"group\":\"TASTE\",\"chart\":\"LINE\"}",
"{\"group\":\"TOP_GAMES\",\"chart\":\"LIST\"}",
"{\"group\":\"TOP_GAMES\",\"chart\":null}",
"{\"group\":\"UNKNOWN\",\"chart\":\"BARS\"}",
"{\"group\":\"platforms\",\"chart\":\"PIE\"}",
"{\"group\":\"PLATFORMS\",\"chart\":\"RADAR\"}",
"{\"chart\":\"PIE\"}",
"{}"
})
void updateStatChart_UnknownGroupOrChart_Is400(String body) throws Exception {
SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken(
new UserPrincipal("1", null), null, Collections.emptyList()));
mockMvc.perform(put("/api/users/settings/stat-chart")
.contentType(MediaType.APPLICATION_JSON)
.content(body))
.andExpect(status().isBadRequest());
verifyNoInteractions(userService);
}
@Test
void updateFavoritePlatform_StoresOrClearsIt() throws Exception {
SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken(
@@ -0,0 +1,54 @@
package auth_service.modules.user.model;
import auth_service.shared.test.AbstractUnitTest;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
import java.util.List;
import java.util.Map;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
class StatChartsTest extends AbstractUnitTest {
@ParameterizedTest
@CsvSource({"TREND,LINE", "TREND,BARS", "FINISHED,BARS", "FINISHED,LINE", "FINISHED,LIST", "TASTE,BARS",
"TASTE,PIE", "TASTE,DONUT", "TASTE,LIST", "PLATFORMS,BARS", "PLATFORMS,PIE", "PLATFORMS,DONUT",
"PLATFORMS,LIST"})
void allows_EachAllowedPair(String group, String chart) {
assertTrue(StatCharts.allows(group, chart));
}
@ParameterizedTest
@CsvSource({"TASTE,LINE", "TOP_GAMES,LIST", "UNKNOWN,BARS", "platforms,PIE", "PLATFORMS,pie", "PLATFORMS,RADAR",
"TREND,PIE"})
void allows_OtherPairs_AreRefused(String group, String chart) {
assertFalse(StatCharts.allows(group, chart));
}
@Test
void knows_OnlyTheChartableGroups() {
assertTrue(StatCharts.knows("PLATFORMS"));
assertFalse(StatCharts.knows("TOP_GAMES"));
assertFalse(StatCharts.knows("platforms"));
}
@Test
void parseAndStored_RoundTripKeepsTheOrder() {
List<String> stored = List.of("TREND:BARS", "PLATFORMS:PIE", "FINISHED:LINE");
Map<String, String> parsed = StatCharts.parse(stored);
assertEquals(stored, List.copyOf(StatCharts.stored(parsed)));
assertEquals("PIE", parsed.get("PLATFORMS"));
assertEquals(List.of("TREND", "PLATFORMS", "FINISHED"), List.copyOf(parsed.keySet()));
}
@Test
void parse_SkipsAnEntryWithoutColon() {
assertEquals(Map.of("TREND", "BARS"), StatCharts.parse(List.of("BROKEN", "TREND:BARS")));
}
}
@@ -17,7 +17,9 @@ import org.springframework.jdbc.core.JdbcTemplate;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import static org.junit.jupiter.api.Assertions.*;
@@ -318,6 +320,29 @@ class UserRepositoryTest extends AbstractPersistenceTest {
assertEquals(profile, saved.getProfileTiles());
}
@Test
void updateStatCharts_StartEmptyAreReadBackAndKeptByUpdateSettings() {
UserEntity userEntity = persisted(UserEntity.builder()
.email("charts@example.com")
.password("password")
.enabled(true)
.registrationDate(LocalDateTime.now())
.build());
assertEquals(Map.of(), findByEmail("charts@example.com").orElseThrow().getSettings().getStatCharts());
Map<String, String> charts = new LinkedHashMap<>();
charts.put("TREND", "BARS");
charts.put("PLATFORMS", "PIE");
userRepository.update(userEntity.getId(), user -> user.getSettings().setStatCharts(charts));
entityManager.flush();
updateSettings(userEntity.getId(), null,
UserSettings.builder().language("de").theme("dark").build());
entityManager.flush();
entityManager.clear();
assertEquals(charts, findByEmail("charts@example.com").orElseThrow().getSettings().getStatCharts());
}
@Test
void updateFavoritePlatform_StoresAndClears() {
UserEntity userEntity = persisted(UserEntity.builder()
@@ -22,6 +22,7 @@ import org.mockito.Mock;
import java.time.Duration;
import java.time.Instant;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.Consumer;
@@ -76,6 +77,31 @@ class UserServiceTest extends AbstractUnitTest {
assertEquals(List.of(new Tile("SUMMARY", "M")), changed.get(1).getSettings().getProfileTiles());
}
@Test
void updateStatChart_PutsTheFormOfTheGroup() {
userService.updateStatChart(1L, "PLATFORMS", "PIE");
userService.updateStatChart(1L, "TREND", "BARS");
List<User> changed = appliedChanges(2);
assertEquals(Map.of("PLATFORMS", "PIE"), changed.get(0).getSettings().getStatCharts());
assertEquals(Map.of("TREND", "BARS"), changed.get(1).getSettings().getStatCharts());
}
@Test
void updateStatChart_KeepsOtherGroupsAndNullRemovesTheEntry() {
UserSettings settings = UserSettings.builder().statCharts(Map.of("PLATFORMS", "PIE", "TREND", "BARS")).build();
User user = User.builder().id(1L).settings(settings).build();
userService.updateStatChart(1L, "PLATFORMS", null);
userService.updateStatChart(1L, "FINISHED", "LINE");
ArgumentCaptor<Consumer<User>> change = ArgumentCaptor.forClass(Consumer.class);
verify(userRepository, times(2)).update(eq(1L), change.capture());
change.getAllValues().get(0).accept(user);
assertEquals(Map.of("TREND", "BARS"), user.getSettings().getStatCharts());
change.getAllValues().get(1).accept(user);
assertEquals(Map.of("TREND", "BARS", "FINISHED", "LINE"), user.getSettings().getStatCharts());
}
@Test
void updateDashboardTiles_NullStaysNull() {
userService.updateDashboardTiles(1L, null);