From 5807fbad76e2b4f2b1e1a81a60ab900980b1fd19 Mon Sep 17 00:00:00 2001 From: iamxvbaba <28732408+iamxvbaba@users.noreply.github.com> Date: Mon, 27 Jul 2026 20:54:04 +0800 Subject: [PATCH] fix(help): sync omit inactive account freeze fields --- internal/app/help/service.go | 16 +++++--------- internal/app/help/service_freeze_test.go | 28 +++++++++--------------- 2 files changed, 15 insertions(+), 29 deletions(-) diff --git a/internal/app/help/service.go b/internal/app/help/service.go index b2d64492..5b7aa8cc 100644 --- a/internal/app/help/service.go +++ b/internal/app/help/service.go @@ -135,8 +135,10 @@ func defaultAppConfigHashFor(mapboxToken string) int { } // GetAppConfig returns the cached global app config plus an authenticated, -// per-account freeze overlay. The overlay owns its own deterministic hash so a -// FROZEN_METHOD_INVALID-triggered refresh can never be answered notModified. +// per-account freeze overlay. Only active freezes add account fields; an +// inactive account receives the field-free base config. The overlay owns its +// own deterministic hash so a FROZEN_METHOD_INVALID-triggered refresh and a +// later unfreeze can never be answered notModified against the other state. func (s *Service) GetAppConfig(ctx context.Context, userID int64, hash int) (domain.AppConfig, bool, error) { cfg := s.loadAppConfig(ctx) var err error @@ -160,15 +162,6 @@ func (s *Service) accountAppConfig(ctx context.Context, userID int64, base domai } } if userID > 0 { - // DrKLO applies only keys present in the new JSON object and retains old - // SharedPreferences values for missing keys. Authenticated non-frozen - // accounts therefore need an explicit zero/empty triplet to converge after - // an unfreeze; merely omitting the overlay works in TDesktop but leaves - // Android frozen indefinitely. Unauthenticated config remains unscoped. - values["freeze_since_date"] = json.RawMessage("0") - values["freeze_until_date"] = json.RawMessage("0") - values["freeze_appeal_url"] = json.RawMessage(`""`) - changed = true if s != nil && s.accountFreeze != nil { freeze, found, err := s.accountFreeze.AccountFreeze(ctx, userID) if err != nil { @@ -179,6 +172,7 @@ func (s *Service) accountAppConfig(ctx context.Context, userID int64, base domai values["freeze_until_date"] = json.RawMessage(strconv.FormatInt(freeze.Until.Unix(), 10)) appeal, _ := json.Marshal(freeze.AppealURL) values["freeze_appeal_url"] = appeal + changed = true } } } diff --git a/internal/app/help/service_freeze_test.go b/internal/app/help/service_freeze_test.go index 26b38810..9cfeccab 100644 --- a/internal/app/help/service_freeze_test.go +++ b/internal/app/help/service_freeze_test.go @@ -46,7 +46,7 @@ func TestAccountAppConfigFreezeOverlayIsUserScopedAndHashAware(t *testing.T) { if err != nil || notModified || other.Hash != normal.Hash { t.Fatalf("other user = hash:%d notModified:%v err:%v", other.Hash, notModified, err) } - assertClearedFreezeConfig(t, other.JSON) + assertNoFreezeConfig(t, other.JSON) unauthorized, _, err := svc.GetAppConfig(context.Background(), 0, 0) if err != nil { t.Fatal(err) @@ -58,21 +58,24 @@ func TestAccountAppConfigFreezeOverlayIsUserScopedAndHashAware(t *testing.T) { if err != nil || notModified || unfrozen.Hash != normal.Hash { t.Fatalf("unfreeze refresh = hash:%d notModified:%v err:%v", unfrozen.Hash, notModified, err) } - assertClearedFreezeConfig(t, unfrozen.JSON) + assertNoFreezeConfig(t, unfrozen.JSON) } -func TestAuthenticatedAppConfigClearsPersistedFreezeWithoutProvider(t *testing.T) { +func TestAuthenticatedNonFrozenAppConfigOmitsFreezeFieldsAndReusesBaseHash(t *testing.T) { svc := NewService(nil, nil) unauthorized, _, err := svc.GetAppConfig(context.Background(), 0, 0) if err != nil { t.Fatal(err) } assertNoFreezeConfig(t, unauthorized.JSON) - authenticated, notModified, err := svc.GetAppConfig(context.Background(), 1001, unauthorized.Hash) - if err != nil || notModified || authenticated.Hash == unauthorized.Hash { - t.Fatalf("authenticated clear config = hash:%d base:%d notModified:%v err:%v", authenticated.Hash, unauthorized.Hash, notModified, err) + authenticated, notModified, err := svc.GetAppConfig(context.Background(), 1001, 0) + if err != nil || notModified || authenticated.Hash != unauthorized.Hash { + t.Fatalf("authenticated config = hash:%d base:%d notModified:%v err:%v", authenticated.Hash, unauthorized.Hash, notModified, err) + } + assertNoFreezeConfig(t, authenticated.JSON) + if _, notModified, err := svc.GetAppConfig(context.Background(), 1001, authenticated.Hash); err != nil || !notModified { + t.Fatalf("authenticated hash replay = notModified:%v err:%v", notModified, err) } - assertClearedFreezeConfig(t, authenticated.JSON) } func TestAccountAppConfigStripsGlobalFreezeFields(t *testing.T) { @@ -112,17 +115,6 @@ func assertNoFreezeConfig(t *testing.T, body []byte) { } } -func assertClearedFreezeConfig(t *testing.T, body []byte) { - t.Helper() - var values map[string]any - if err := json.Unmarshal(body, &values); err != nil { - t.Fatal(err) - } - if values["freeze_since_date"] != float64(0) || values["freeze_until_date"] != float64(0) || values["freeze_appeal_url"] != "" { - t.Fatalf("freeze clear config = %#v", values) - } -} - type fakeAccountFreezeProvider struct { items map[int64]domain.AccountFreeze }