feat(profile): keep_screen_awake user preference (default on)
New users column surfaced as an On/Off dropdown in the profile form. The form and API carry "true"/"false" strings with the theme-style ""-guard, so JSON clients that omit the field can't clobber it; anything else is rejected. GET/PUT /api/auth/profile expose keep_screen_awake alongside the other profile fields, and the reader route threads the preference into its template metadata. Integration tests pin the schema default, both values, omission semantics, and rejection — dedicated test user, never testuser.
This commit is contained in:
1 parent
bdb9132b85
commit
c645b8e207
12 files changed
+244
-67
No files matched your search
@@ -667,3 +667,92 @@ func TestUpdatePasswordSelfChange(t *testing.T) {
|
||||
assert.Contains(t, rec.Body.String(), "current password required")
|
||||
})
|
||||
}
|
||||
|
||||
// TestProfileKeepScreenAwake pins the keep_screen_awake user preference
|
||||
// end to end: schema default, the "true"/"false" form dropdown contract,
|
||||
// JSON-client omission semantics ("" = untouched), and rejection of
|
||||
// anything else. Uses a dedicated user — never the shared admin.
|
||||
func TestProfileKeepScreenAwake(t *testing.T) {
|
||||
// getProfile fetches the JSON profile and returns keep_screen_awake.
|
||||
getProfile := func(t *testing.T, setup *TestServerSetup, token string) bool {
|
||||
req := httptest.NewRequest("GET", "/api/auth/profile", nil)
|
||||
req.Header.Set("Authorization", "Bearer "+token)
|
||||
rec := httptest.NewRecorder()
|
||||
setup.Server.Config.Handler.ServeHTTP(rec, req)
|
||||
require.Equal(t, http.StatusOK, rec.Code)
|
||||
var body struct {
|
||||
KeepScreenAwake bool `json:"keep_screen_awake"`
|
||||
}
|
||||
require.NoError(t, json.Unmarshal(rec.Body.Bytes(), &body))
|
||||
return body.KeepScreenAwake
|
||||
}
|
||||
putProfile := func(t *testing.T, setup *TestServerSetup, token string, fields map[string]interface{}) *httptest.ResponseRecorder {
|
||||
jsonData, _ := json.Marshal(fields)
|
||||
req := httptest.NewRequest("PUT", "/api/auth/profile", bytes.NewBuffer(jsonData))
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
req.Header.Set("Authorization", "Bearer "+token)
|
||||
rec := httptest.NewRecorder()
|
||||
setup.Server.Config.Handler.ServeHTTP(rec, req)
|
||||
return rec
|
||||
}
|
||||
|
||||
t.Run("fresh user defaults to true", func(t *testing.T) {
|
||||
setup := setupTestServer(t)
|
||||
selfUser := createRegularUserOnce(t, setup.DB)
|
||||
token := loginUserWithCredentials(t, setup.Server, selfUser.Email, selfUser.Password)
|
||||
|
||||
row, err := setup.DB.GetUser(context.Background(), pgtype.UUID{Bytes: selfUser.ID, Valid: true})
|
||||
require.NoError(t, err)
|
||||
assert.True(t, row.KeepScreenAwake, "schema default must keep the column TRUE")
|
||||
assert.True(t, getProfile(t, setup, token), "profile API must report the default")
|
||||
})
|
||||
|
||||
t.Run("false persists and reads back", func(t *testing.T) {
|
||||
setup := setupTestServer(t)
|
||||
selfUser := createRegularUserOnce(t, setup.DB)
|
||||
token := loginUserWithCredentials(t, setup.Server, selfUser.Email, selfUser.Password)
|
||||
|
||||
rec := putProfile(t, setup, token, map[string]interface{}{"keep_screen_awake": "false"})
|
||||
require.Equal(t, http.StatusOK, rec.Code)
|
||||
assert.False(t, getProfile(t, setup, token))
|
||||
|
||||
row, err := setup.DB.GetUser(context.Background(), pgtype.UUID{Bytes: selfUser.ID, Valid: true})
|
||||
require.NoError(t, err)
|
||||
assert.False(t, row.KeepScreenAwake)
|
||||
})
|
||||
|
||||
t.Run("flipping back to true persists", func(t *testing.T) {
|
||||
setup := setupTestServer(t)
|
||||
selfUser := createRegularUserOnce(t, setup.DB)
|
||||
token := loginUserWithCredentials(t, setup.Server, selfUser.Email, selfUser.Password)
|
||||
|
||||
require.Equal(t, http.StatusOK, putProfile(t, setup, token,
|
||||
map[string]interface{}{"keep_screen_awake": "false"}).Code)
|
||||
require.Equal(t, http.StatusOK, putProfile(t, setup, token,
|
||||
map[string]interface{}{"keep_screen_awake": "true"}).Code)
|
||||
assert.True(t, getProfile(t, setup, token))
|
||||
})
|
||||
|
||||
t.Run("request omitting the field leaves it untouched", func(t *testing.T) {
|
||||
setup := setupTestServer(t)
|
||||
selfUser := createRegularUserOnce(t, setup.DB)
|
||||
token := loginUserWithCredentials(t, setup.Server, selfUser.Email, selfUser.Password)
|
||||
|
||||
// JSON clients (the Android app) sync other profile fields
|
||||
// without knowing this one — the default-on preference must
|
||||
// survive such a save.
|
||||
rec := putProfile(t, setup, token, map[string]interface{}{"theme": "nord"})
|
||||
require.Equal(t, http.StatusOK, rec.Code)
|
||||
assert.True(t, getProfile(t, setup, token))
|
||||
})
|
||||
|
||||
t.Run("invalid value is rejected", func(t *testing.T) {
|
||||
setup := setupTestServer(t)
|
||||
selfUser := createRegularUserOnce(t, setup.DB)
|
||||
token := loginUserWithCredentials(t, setup.Server, selfUser.Email, selfUser.Password)
|
||||
|
||||
rec := putProfile(t, setup, token, map[string]interface{}{"keep_screen_awake": "maybe"})
|
||||
assert.Equal(t, http.StatusBadRequest, rec.Code)
|
||||
assert.True(t, getProfile(t, setup, token), "rejected save must not change the preference")
|
||||
})
|
||||
}
|
||||
Reference in new issue
Block a user