feat: show available reset credits

This commit is contained in:
2026-08-22 09:59:10 +08:00
parent 45ceeee936
commit 6a711c1fff
12 changed files with 201 additions and 21 deletions
+37 -6
View File
@@ -6,6 +6,7 @@ import (
"errors"
"net/http"
"net/http/httptest"
"reflect"
"strconv"
"strings"
"sync"
@@ -93,12 +94,13 @@ func TestAnonymousOverviewIsReadOnly(t *testing.T) {
}
a.runtimes[1] = &accountRuntime{
dash: Dashboard{
AccountID: 1,
DisplayName: "默认账号",
Account: AccountView{Email: &email, PlanType: &plan, Connected: true},
Limits: []LimitBucket{},
Usage: []UsagePoint{},
FetchedAt: time.Now().Unix(),
AccountID: 1,
DisplayName: "默认账号",
Account: AccountView{Email: &email, PlanType: &plan, Connected: true},
Limits: []LimitBucket{},
Usage: []UsagePoint{},
ResetCredits: &ResetCreditsSummary{AvailableCount: 2, ExpiresAt: []int64{1784246400}},
FetchedAt: time.Now().Unix(),
},
}
@@ -132,6 +134,9 @@ func TestAnonymousOverviewIsReadOnly(t *testing.T) {
if publicDashboardBody.Account.Email != nil || publicDashboardBody.Account.AuthMode != nil {
t.Fatalf("anonymous dashboard account = %#v; identity fields were not redacted", publicDashboardBody.Account)
}
if publicDashboardBody.ResetCredits != nil {
t.Fatalf("anonymous dashboard reset credits = %#v; entitlement data was not redacted", publicDashboardBody.ResetCredits)
}
for _, path := range []string{"/api/v1/settings/general", "/api/v1/accounts", "/api/v1/accounts/1/sync"} {
recorder := httptest.NewRecorder()
@@ -163,6 +168,9 @@ func TestAnonymousOverviewIsReadOnly(t *testing.T) {
if privateDashboardBody.Account.Email == nil || *privateDashboardBody.Account.Email != email {
t.Fatalf("authenticated dashboard email = %v; want %q", privateDashboardBody.Account.Email, email)
}
if privateDashboardBody.ResetCredits == nil || privateDashboardBody.ResetCredits.AvailableCount != 2 {
t.Fatalf("authenticated dashboard reset credits = %#v; want two credits", privateDashboardBody.ResetCredits)
}
configRecorder := httptest.NewRecorder()
configRequest := httptest.NewRequest(http.MethodPut, "/api/v1/settings/general", strings.NewReader(`{"timezone":"UTC","theme":"system","syncMinutes":5,"retentionDays":90,"beforeMinutes":30,"notifyBefore":true,"notifyAfter":true}`))
configRequest.AddCookie(&http.Cookie{Name: "session", Value: session})
@@ -320,6 +328,29 @@ func TestCurrentTokenCycleUsesLongestWindowAndFiltersDailyUsage(t *testing.T) {
}
}
func TestNormalizeResetCreditsKeepsAvailableCountAndUniqueExpiryTimes(t *testing.T) {
earlier := int64(1781654400)
later := int64(1784246400)
credits := normalizeResetCredits(&rawResetCredits{
AvailableCount: 3,
Credits: []rawResetCredit{
{ExpiresAt: &later},
{ExpiresAt: nil},
{ExpiresAt: &earlier},
{ExpiresAt: &later},
},
})
if credits == nil || credits.AvailableCount != 3 {
t.Fatalf("reset credits = %#v; want three available credits", credits)
}
if want := []int64{earlier, later}; !reflect.DeepEqual(credits.ExpiresAt, want) {
t.Fatalf("expiry times = %v; want %v", credits.ExpiresAt, want)
}
if normalizeResetCredits(&rawResetCredits{}) != nil {
t.Fatal("zero available credits should be hidden")
}
}
func TestCurrentTokenCycleRequiresAValidFutureResetWindow(t *testing.T) {
cycle := currentTokenCycle(
[]LimitBucket{{WindowDurationMinutes: 0, ResetsAt: 1}},