Public Access
feat(user): pick or turn off the dashboard banner
This commit is contained in:
1 parent
e04fd27b08
commit
af386bb8f7
11 files changed
+46
-20
No files matched your search
@@ -11,5 +11,7 @@ public record AppearanceRequest(
|
|||||||
@NotNull @Pattern(regexp = "violet|blue|green|orange|pink|red") String accent,
|
@NotNull @Pattern(regexp = "violet|blue|green|orange|pink|red") String accent,
|
||||||
@NotNull @Pattern(regexp = "sharp|default|round") String corners,
|
@NotNull @Pattern(regexp = "sharp|default|round") String corners,
|
||||||
Boolean wideLayout,
|
Boolean wideLayout,
|
||||||
@Positive Long backgroundAppid) {
|
@Positive Long backgroundAppid,
|
||||||
|
@Positive Long bannerAppid,
|
||||||
|
Boolean showBanner) {
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
package auth_service.modules.user.api.dto.response;
|
package auth_service.modules.user.api.dto.response;
|
||||||
|
|
||||||
public record AppearanceResponse(String accent, String corners, boolean wideLayout, Long backgroundAppid) {
|
public record AppearanceResponse(String accent, String corners, boolean wideLayout, Long backgroundAppid,
|
||||||
|
Long bannerAppid, boolean showBanner) {
|
||||||
}
|
}
|
||||||
@@ -35,12 +35,13 @@ public abstract class ApiMapper {
|
|||||||
|
|
||||||
private static AppearanceResponse toApi(Appearance appearance) {
|
private static AppearanceResponse toApi(Appearance appearance) {
|
||||||
return new AppearanceResponse(appearance.accent(), appearance.corners(), appearance.wideLayout(),
|
return new AppearanceResponse(appearance.accent(), appearance.corners(), appearance.wideLayout(),
|
||||||
appearance.backgroundAppid());
|
appearance.backgroundAppid(), appearance.bannerAppid(), appearance.showBanner());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Appearance toDomain(AppearanceRequest request) {
|
public static Appearance toDomain(AppearanceRequest request) {
|
||||||
|
// A missing showBanner keeps the banner on, the default.
|
||||||
return new Appearance(request.accent(), request.corners(), Boolean.TRUE.equals(request.wideLayout()),
|
return new Appearance(request.accent(), request.corners(), Boolean.TRUE.equals(request.wideLayout()),
|
||||||
request.backgroundAppid());
|
request.backgroundAppid(), request.bannerAppid(), !Boolean.FALSE.equals(request.showBanner()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Long toSteamId(UserSettingsRequest request) {
|
public static Long toSteamId(UserSettingsRequest request) {
|
||||||
|
|||||||
@@ -2,8 +2,11 @@ package auth_service.modules.user.model;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @param backgroundAppid the Steam app whose art fills the page background; null for none
|
* @param backgroundAppid the Steam app whose art fills the page background; null for none
|
||||||
|
* @param bannerAppid the Steam app whose art is the dashboard banner; null for the most played game of the last
|
||||||
|
* two weeks
|
||||||
*/
|
*/
|
||||||
public record Appearance(String accent, String corners, boolean wideLayout, Long backgroundAppid) {
|
public record Appearance(String accent, String corners, boolean wideLayout, Long backgroundAppid,
|
||||||
|
Long bannerAppid, boolean showBanner) {
|
||||||
|
|
||||||
public static final Appearance DEFAULT = new Appearance("violet", "default", false, null);
|
public static final Appearance DEFAULT = new Appearance("violet", "default", false, null, null, true);
|
||||||
}
|
}
|
||||||
@@ -109,6 +109,8 @@ public class UserRepositoryImpl implements UserRepository {
|
|||||||
settingsEntity.setCorners(appearance.corners());
|
settingsEntity.setCorners(appearance.corners());
|
||||||
settingsEntity.setWideLayout(appearance.wideLayout());
|
settingsEntity.setWideLayout(appearance.wideLayout());
|
||||||
settingsEntity.setBackgroundAppid(appearance.backgroundAppid());
|
settingsEntity.setBackgroundAppid(appearance.backgroundAppid());
|
||||||
|
settingsEntity.setBannerAppid(appearance.bannerAppid());
|
||||||
|
settingsEntity.setShowBanner(appearance.showBanner());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -40,4 +40,10 @@ public class UserSettingsEntity {
|
|||||||
|
|
||||||
@Column(name = "background_appid")
|
@Column(name = "background_appid")
|
||||||
private Long backgroundAppid;
|
private Long backgroundAppid;
|
||||||
|
|
||||||
|
@Column(name = "banner_appid")
|
||||||
|
private Long bannerAppid;
|
||||||
|
|
||||||
|
@Column(name = "show_banner", nullable = false)
|
||||||
|
private boolean showBanner = Appearance.DEFAULT.showBanner();
|
||||||
}
|
}
|
||||||
@@ -24,7 +24,8 @@ public abstract class EntityMapper {
|
|||||||
.theme(entity.getSettings().getTheme())
|
.theme(entity.getSettings().getTheme())
|
||||||
.publicProfile(entity.getSettings().isPublicProfile())
|
.publicProfile(entity.getSettings().isPublicProfile())
|
||||||
.appearance(new Appearance(entity.getSettings().getAccent(), entity.getSettings().getCorners(),
|
.appearance(new Appearance(entity.getSettings().getAccent(), entity.getSettings().getCorners(),
|
||||||
entity.getSettings().isWideLayout(), entity.getSettings().getBackgroundAppid()))
|
entity.getSettings().isWideLayout(), entity.getSettings().getBackgroundAppid(),
|
||||||
|
entity.getSettings().getBannerAppid(), entity.getSettings().isShowBanner()))
|
||||||
.build();
|
.build();
|
||||||
} else {
|
} else {
|
||||||
// Fallback default settings for users without an entry in the database
|
// Fallback default settings for users without an entry in the database
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
-- The dashboard banner: a picked game, or the most played game of the last two weeks when NULL.
|
||||||
|
ALTER TABLE user_settings
|
||||||
|
ADD COLUMN banner_appid BIGINT,
|
||||||
|
ADD COLUMN show_banner BOOLEAN NOT NULL DEFAULT TRUE;
|
||||||
@@ -407,7 +407,7 @@ class UserControllerTest extends AbstractWebMvcTest {
|
|||||||
void getCurrentUserV1_ShowsAppearance() throws Exception {
|
void getCurrentUserV1_ShowsAppearance() throws Exception {
|
||||||
var email = "test@example.com";
|
var email = "test@example.com";
|
||||||
var settings = UserSettings.builder().language("en").theme("dark")
|
var settings = UserSettings.builder().language("en").theme("dark")
|
||||||
.appearance(new Appearance("blue", "round", true, 620L)).build();
|
.appearance(new Appearance("blue", "round", true, 620L, 1086940L, false)).build();
|
||||||
SecurityContextHolder.getContext().setAuthentication(
|
SecurityContextHolder.getContext().setAuthentication(
|
||||||
new UsernamePasswordAuthenticationToken(new UserPrincipal("1", email, null), null, Collections.emptyList())
|
new UsernamePasswordAuthenticationToken(new UserPrincipal("1", email, null), null, Collections.emptyList())
|
||||||
);
|
);
|
||||||
@@ -418,7 +418,9 @@ class UserControllerTest extends AbstractWebMvcTest {
|
|||||||
.andExpect(jsonPath("$.settings.appearance.accent").value("blue"))
|
.andExpect(jsonPath("$.settings.appearance.accent").value("blue"))
|
||||||
.andExpect(jsonPath("$.settings.appearance.corners").value("round"))
|
.andExpect(jsonPath("$.settings.appearance.corners").value("round"))
|
||||||
.andExpect(jsonPath("$.settings.appearance.wideLayout").value(true))
|
.andExpect(jsonPath("$.settings.appearance.wideLayout").value(true))
|
||||||
.andExpect(jsonPath("$.settings.appearance.backgroundAppid").value(620));
|
.andExpect(jsonPath("$.settings.appearance.backgroundAppid").value(620))
|
||||||
|
.andExpect(jsonPath("$.settings.appearance.bannerAppid").value(1086940))
|
||||||
|
.andExpect(jsonPath("$.settings.appearance.showBanner").value(false));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -435,7 +437,9 @@ class UserControllerTest extends AbstractWebMvcTest {
|
|||||||
.andExpect(jsonPath("$.settings.appearance.accent").value("violet"))
|
.andExpect(jsonPath("$.settings.appearance.accent").value("violet"))
|
||||||
.andExpect(jsonPath("$.settings.appearance.corners").value("default"))
|
.andExpect(jsonPath("$.settings.appearance.corners").value("default"))
|
||||||
.andExpect(jsonPath("$.settings.appearance.wideLayout").value(false))
|
.andExpect(jsonPath("$.settings.appearance.wideLayout").value(false))
|
||||||
.andExpect(jsonPath("$.settings.appearance.backgroundAppid").isEmpty());
|
.andExpect(jsonPath("$.settings.appearance.backgroundAppid").isEmpty())
|
||||||
|
.andExpect(jsonPath("$.settings.appearance.bannerAppid").isEmpty())
|
||||||
|
.andExpect(jsonPath("$.settings.appearance.showBanner").value(true));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -445,14 +449,15 @@ class UserControllerTest extends AbstractWebMvcTest {
|
|||||||
|
|
||||||
mockMvc.perform(put("/api/users/settings/appearance")
|
mockMvc.perform(put("/api/users/settings/appearance")
|
||||||
.contentType(MediaType.APPLICATION_JSON)
|
.contentType(MediaType.APPLICATION_JSON)
|
||||||
.content("{\"accent\":\"green\",\"corners\":\"sharp\",\"wideLayout\":true,\"backgroundAppid\":620}"))
|
.content("{\"accent\":\"green\",\"corners\":\"sharp\",\"wideLayout\":true,\"backgroundAppid\":620,"
|
||||||
|
+ "\"bannerAppid\":1086940,\"showBanner\":false}"))
|
||||||
.andExpect(status().isNoContent());
|
.andExpect(status().isNoContent());
|
||||||
|
|
||||||
verify(userService).updateAppearance(1L, new Appearance("green", "sharp", true, 620L));
|
verify(userService).updateAppearance(1L, new Appearance("green", "sharp", true, 620L, 1086940L, false));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void updateAppearance_MissingWideLayoutAndBackground_AreOffAndNone() throws Exception {
|
void updateAppearance_MissingOptionalFields_AreTheDefaults() throws Exception {
|
||||||
SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken(
|
SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken(
|
||||||
new UserPrincipal("1", "test@example.com", null), null, Collections.emptyList()));
|
new UserPrincipal("1", "test@example.com", null), null, Collections.emptyList()));
|
||||||
|
|
||||||
@@ -461,7 +466,7 @@ class UserControllerTest extends AbstractWebMvcTest {
|
|||||||
.content("{\"accent\":\"violet\",\"corners\":\"default\"}"))
|
.content("{\"accent\":\"violet\",\"corners\":\"default\"}"))
|
||||||
.andExpect(status().isNoContent());
|
.andExpect(status().isNoContent());
|
||||||
|
|
||||||
verify(userService).updateAppearance(1L, new Appearance("violet", "default", false, null));
|
verify(userService).updateAppearance(1L, new Appearance("violet", "default", false, null, null, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Each body differs from a valid one in one field only, so the 400 comes from that field's constraint.
|
// Each body differs from a valid one in one field only, so the 400 comes from that field's constraint.
|
||||||
@@ -473,7 +478,8 @@ class UserControllerTest extends AbstractWebMvcTest {
|
|||||||
"{\"accent\":\"violet\",\"corners\":\"pointy\"}",
|
"{\"accent\":\"violet\",\"corners\":\"pointy\"}",
|
||||||
"{\"accent\":\"violet\"}",
|
"{\"accent\":\"violet\"}",
|
||||||
"{\"accent\":\"violet\",\"corners\":\"default\",\"backgroundAppid\":0}",
|
"{\"accent\":\"violet\",\"corners\":\"default\",\"backgroundAppid\":0}",
|
||||||
"{\"accent\":\"violet\",\"corners\":\"default\",\"backgroundAppid\":-620}"
|
"{\"accent\":\"violet\",\"corners\":\"default\",\"backgroundAppid\":-620}",
|
||||||
|
"{\"accent\":\"violet\",\"corners\":\"default\",\"bannerAppid\":0}"
|
||||||
})
|
})
|
||||||
void updateAppearance_UnknownOrMissingValue_IsRejected(String body) throws Exception {
|
void updateAppearance_UnknownOrMissingValue_IsRejected(String body) throws Exception {
|
||||||
SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken(
|
SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken(
|
||||||
|
|||||||
@@ -210,12 +210,12 @@ class UserRepositoryTest extends AbstractPersistenceTest {
|
|||||||
.build());
|
.build());
|
||||||
entityManager.flush();
|
entityManager.flush();
|
||||||
|
|
||||||
userRepository.updateAppearance(userEntity.getId(), new Appearance("orange", "round", true, 620L));
|
userRepository.updateAppearance(userEntity.getId(), new Appearance("orange", "round", true, 620L, 1086940L, false));
|
||||||
entityManager.flush();
|
entityManager.flush();
|
||||||
entityManager.clear();
|
entityManager.clear();
|
||||||
|
|
||||||
var settings = userRepository.findByEmail("appearance@example.com").orElseThrow().getSettings();
|
var settings = userRepository.findByEmail("appearance@example.com").orElseThrow().getSettings();
|
||||||
assertEquals(new Appearance("orange", "round", true, 620L), settings.getAppearance());
|
assertEquals(new Appearance("orange", "round", true, 620L, 1086940L, false), settings.getAppearance());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -227,7 +227,7 @@ class UserRepositoryTest extends AbstractPersistenceTest {
|
|||||||
.registrationDate(LocalDateTime.now())
|
.registrationDate(LocalDateTime.now())
|
||||||
.build());
|
.build());
|
||||||
entityManager.flush();
|
entityManager.flush();
|
||||||
userRepository.updateAppearance(userEntity.getId(), new Appearance("pink", "sharp", false, 220L));
|
userRepository.updateAppearance(userEntity.getId(), new Appearance("pink", "sharp", false, 220L, null, true));
|
||||||
entityManager.flush();
|
entityManager.flush();
|
||||||
|
|
||||||
userRepository.updateSettings(userEntity.getId(), null, null,
|
userRepository.updateSettings(userEntity.getId(), null, null,
|
||||||
@@ -236,7 +236,7 @@ class UserRepositoryTest extends AbstractPersistenceTest {
|
|||||||
entityManager.clear();
|
entityManager.clear();
|
||||||
|
|
||||||
var settings = userRepository.findByEmail("keep@example.com").orElseThrow().getSettings();
|
var settings = userRepository.findByEmail("keep@example.com").orElseThrow().getSettings();
|
||||||
assertEquals(new Appearance("pink", "sharp", false, 220L), settings.getAppearance());
|
assertEquals(new Appearance("pink", "sharp", false, 220L, null, true), settings.getAppearance());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
@@ -135,7 +135,7 @@ class UserServiceTest extends AbstractUnitTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
void updateAppearance_StoresItWithoutANewToken() {
|
void updateAppearance_StoresItWithoutANewToken() {
|
||||||
var appearance = new Appearance("red", "round", false, null);
|
var appearance = new Appearance("red", "round", false, null, null, true);
|
||||||
|
|
||||||
userService.updateAppearance(1L, appearance);
|
userService.updateAppearance(1L, appearance);
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user