fix: gofmt formatting across all Go source files

This commit is contained in:
erio
2026-04-14 07:43:08 +08:00
parent 9e0d12d3b0
commit 1e6912ea2e
18 changed files with 143 additions and 84 deletions

View File

@@ -310,11 +310,11 @@ type UpdateSettingsRequest struct {
EnableCCHSigning *bool `json:"enable_cch_signing"` EnableCCHSigning *bool `json:"enable_cch_signing"`
// Balance low notification // Balance low notification
BalanceLowNotifyEnabled *bool `json:"balance_low_notify_enabled"` BalanceLowNotifyEnabled *bool `json:"balance_low_notify_enabled"`
BalanceLowNotifyThreshold *float64 `json:"balance_low_notify_threshold"` BalanceLowNotifyThreshold *float64 `json:"balance_low_notify_threshold"`
BalanceLowNotifyRechargeURL *string `json:"balance_low_notify_recharge_url"` BalanceLowNotifyRechargeURL *string `json:"balance_low_notify_recharge_url"`
AccountQuotaNotifyEnabled *bool `json:"account_quota_notify_enabled"` AccountQuotaNotifyEnabled *bool `json:"account_quota_notify_enabled"`
AccountQuotaNotifyEmails *[]dto.NotifyEmailEntry `json:"account_quota_notify_emails"` AccountQuotaNotifyEmails *[]dto.NotifyEmailEntry `json:"account_quota_notify_emails"`
// Payment configuration (integrated into settings, full replace) // Payment configuration (integrated into settings, full replace)
PaymentEnabled *bool `json:"payment_enabled"` PaymentEnabled *bool `json:"payment_enabled"`

View File

@@ -150,11 +150,11 @@ type SystemSettings struct {
PaymentCancelRateLimitMode string `json:"payment_cancel_rate_limit_window_mode"` PaymentCancelRateLimitMode string `json:"payment_cancel_rate_limit_window_mode"`
// Balance low notification // Balance low notification
BalanceLowNotifyEnabled bool `json:"balance_low_notify_enabled"` BalanceLowNotifyEnabled bool `json:"balance_low_notify_enabled"`
BalanceLowNotifyThreshold float64 `json:"balance_low_notify_threshold"` BalanceLowNotifyThreshold float64 `json:"balance_low_notify_threshold"`
BalanceLowNotifyRechargeURL string `json:"balance_low_notify_recharge_url"` BalanceLowNotifyRechargeURL string `json:"balance_low_notify_recharge_url"`
AccountQuotaNotifyEnabled bool `json:"account_quota_notify_enabled"` AccountQuotaNotifyEnabled bool `json:"account_quota_notify_enabled"`
AccountQuotaNotifyEmails []NotifyEmailEntry `json:"account_quota_notify_emails"` AccountQuotaNotifyEmails []NotifyEmailEntry `json:"account_quota_notify_emails"`
} }
type DefaultSubscriptionSetting struct { type DefaultSubscriptionSetting struct {

View File

@@ -19,11 +19,11 @@ type User struct {
UpdatedAt time.Time `json:"updated_at"` UpdatedAt time.Time `json:"updated_at"`
// 余额不足通知 // 余额不足通知
BalanceNotifyEnabled bool `json:"balance_notify_enabled"` BalanceNotifyEnabled bool `json:"balance_notify_enabled"`
BalanceNotifyThresholdType string `json:"balance_notify_threshold_type"` BalanceNotifyThresholdType string `json:"balance_notify_threshold_type"`
BalanceNotifyThreshold *float64 `json:"balance_notify_threshold"` BalanceNotifyThreshold *float64 `json:"balance_notify_threshold"`
BalanceNotifyExtraEmails []NotifyEmailEntry `json:"balance_notify_extra_emails"` BalanceNotifyExtraEmails []NotifyEmailEntry `json:"balance_notify_extra_emails"`
TotalRecharged float64 `json:"total_recharged"` TotalRecharged float64 `json:"total_recharged"`
APIKeys []APIKey `json:"api_keys,omitempty"` APIKeys []APIKey `json:"api_keys,omitempty"`
Subscriptions []UserSubscription `json:"subscriptions,omitempty"` Subscriptions []UserSubscription `json:"subscriptions,omitempty"`

View File

@@ -242,7 +242,7 @@ func TestFilterByLimits(t *testing.T) {
wantIDs: nil, wantIDs: nil,
}, },
{ {
name: "empty candidates returns empty", name: "empty candidates returns empty",
candidates: nil, candidates: nil,
paymentType: "alipay", paymentType: "alipay",
orderAmount: 10, orderAmount: 10,

View File

@@ -98,9 +98,9 @@ func TestNewAlipay(t *testing.T) {
errSubstr: "privateKey", errSubstr: "privateKey",
}, },
{ {
name: "nil config map returns error for appId", name: "nil config map returns error for appId",
config: map[string]string{}, config: map[string]string{},
wantErr: true, wantErr: true,
errSubstr: "appId", errSubstr: "appId",
}, },
} }

View File

@@ -1533,39 +1533,48 @@ func (a *Account) QuotaNotifyConfig(dim string) (enabled bool, threshold float64
} }
func (a *Account) GetQuotaNotifyDailyEnabled() bool { func (a *Account) GetQuotaNotifyDailyEnabled() bool {
e, _, _ := a.QuotaNotifyConfig(quotaDimDaily); return e e, _, _ := a.QuotaNotifyConfig(quotaDimDaily)
return e
} }
func (a *Account) GetQuotaNotifyDailyThreshold() float64 { func (a *Account) GetQuotaNotifyDailyThreshold() float64 {
_, t, _ := a.QuotaNotifyConfig(quotaDimDaily); return t _, t, _ := a.QuotaNotifyConfig(quotaDimDaily)
return t
} }
func (a *Account) GetQuotaNotifyDailyThresholdType() string { func (a *Account) GetQuotaNotifyDailyThresholdType() string {
_, _, tt := a.QuotaNotifyConfig(quotaDimDaily); return tt _, _, tt := a.QuotaNotifyConfig(quotaDimDaily)
return tt
} }
func (a *Account) GetQuotaNotifyWeeklyEnabled() bool { func (a *Account) GetQuotaNotifyWeeklyEnabled() bool {
e, _, _ := a.QuotaNotifyConfig(quotaDimWeekly); return e e, _, _ := a.QuotaNotifyConfig(quotaDimWeekly)
return e
} }
func (a *Account) GetQuotaNotifyWeeklyThreshold() float64 { func (a *Account) GetQuotaNotifyWeeklyThreshold() float64 {
_, t, _ := a.QuotaNotifyConfig(quotaDimWeekly); return t _, t, _ := a.QuotaNotifyConfig(quotaDimWeekly)
return t
} }
func (a *Account) GetQuotaNotifyWeeklyThresholdType() string { func (a *Account) GetQuotaNotifyWeeklyThresholdType() string {
_, _, tt := a.QuotaNotifyConfig(quotaDimWeekly); return tt _, _, tt := a.QuotaNotifyConfig(quotaDimWeekly)
return tt
} }
func (a *Account) GetQuotaNotifyTotalEnabled() bool { func (a *Account) GetQuotaNotifyTotalEnabled() bool {
e, _, _ := a.QuotaNotifyConfig(quotaDimTotal); return e e, _, _ := a.QuotaNotifyConfig(quotaDimTotal)
return e
} }
func (a *Account) GetQuotaNotifyTotalThreshold() float64 { func (a *Account) GetQuotaNotifyTotalThreshold() float64 {
_, t, _ := a.QuotaNotifyConfig(quotaDimTotal); return t _, t, _ := a.QuotaNotifyConfig(quotaDimTotal)
return t
} }
func (a *Account) GetQuotaNotifyTotalThresholdType() string { func (a *Account) GetQuotaNotifyTotalThresholdType() string {
_, _, tt := a.QuotaNotifyConfig(quotaDimTotal); return tt _, _, tt := a.QuotaNotifyConfig(quotaDimTotal)
return tt
} }
// nextFixedDailyReset 计算在 after 之后的下一个每日固定重置时间点 // nextFixedDailyReset 计算在 after 之后的下一个每日固定重置时间点

View File

@@ -65,15 +65,15 @@ func TestBuildBalanceLowEmailBody_NoRechargeURLOmitsButton(t *testing.T) {
func TestBuildQuotaAlertEmailBody_AllFieldsPresent(t *testing.T) { func TestBuildQuotaAlertEmailBody_AllFieldsPresent(t *testing.T) {
s := &BalanceNotifyService{} s := &BalanceNotifyService{}
body := s.buildQuotaAlertEmailBody( body := s.buildQuotaAlertEmailBody(
42, // accountID 42, // accountID
"acc-foo", // accountName "acc-foo", // accountName
"anthropic", // platform "anthropic", // platform
"日限额 / Daily", // dimLabel "日限额 / Daily", // dimLabel
750.50, // used 750.50, // used
1000.0, // limit 1000.0, // limit
249.50, // remaining 249.50, // remaining
"$249.50", // thresholdDisplay "$249.50", // thresholdDisplay
"MySite", // siteName "MySite", // siteName
) )
require.Contains(t, body, "MySite") require.Contains(t, body, "MySite")

View File

@@ -251,8 +251,8 @@ const (
SettingKeyEnableCCHSigning = "enable_cch_signing" SettingKeyEnableCCHSigning = "enable_cch_signing"
// Balance Low Notification // Balance Low Notification
SettingKeyBalanceLowNotifyEnabled = "balance_low_notify_enabled" // 全局开关 SettingKeyBalanceLowNotifyEnabled = "balance_low_notify_enabled" // 全局开关
SettingKeyBalanceLowNotifyThreshold = "balance_low_notify_threshold" // 默认阈值USD SettingKeyBalanceLowNotifyThreshold = "balance_low_notify_threshold" // 默认阈值USD
SettingKeyBalanceLowNotifyRechargeURL = "balance_low_notify_recharge_url" // 充值页面 URL SettingKeyBalanceLowNotifyRechargeURL = "balance_low_notify_recharge_url" // 充值页面 URL
// Account Quota Notification // Account Quota Notification

View File

@@ -131,9 +131,9 @@ func TestValidatePlanPatch_NilOriginalPrice(t *testing.T) {
// --- validatePlanPatch: other fields --- // --- validatePlanPatch: other fields ---
func ptrStr(s string) *string { return &s } func ptrStr(s string) *string { return &s }
func ptrInt(i int) *int { return &i } func ptrInt(i int) *int { return &i }
func ptrInt64(i int64) *int64 { return &i } func ptrInt64(i int64) *int64 { return &i }
func ptrFloat(f float64) *float64 { return &f } func ptrFloat(f float64) *float64 { return &f }
func TestValidatePlanPatch_EmptyName(t *testing.T) { func TestValidatePlanPatch_EmptyName(t *testing.T) {

View File

@@ -22,16 +22,17 @@ func (s *PaymentConfigService) ListProviderInstances(ctx context.Context) ([]*db
// ProviderInstanceResponse is the API response for a provider instance. // ProviderInstanceResponse is the API response for a provider instance.
type ProviderInstanceResponse struct { type ProviderInstanceResponse struct {
ID int64 `json:"id"` ID int64 `json:"id"`
ProviderKey string `json:"provider_key"` ProviderKey string `json:"provider_key"`
Name string `json:"name"` Name string `json:"name"`
Config map[string]string `json:"config"` Config map[string]string `json:"config"`
SupportedTypes []string `json:"supported_types"` SupportedTypes []string `json:"supported_types"`
Limits string `json:"limits"` Limits string `json:"limits"`
Enabled bool `json:"enabled"` Enabled bool `json:"enabled"`
RefundEnabled bool `json:"refund_enabled"` RefundEnabled bool `json:"refund_enabled"`
SortOrder int `json:"sort_order"` AllowUserRefund bool `json:"allow_user_refund"`
PaymentMode string `json:"payment_mode"` SortOrder int `json:"sort_order"`
PaymentMode string `json:"payment_mode"`
} }
// ListProviderInstancesWithConfig returns provider instances with decrypted config. // ListProviderInstancesWithConfig returns provider instances with decrypted config.
@@ -46,8 +47,8 @@ func (s *PaymentConfigService) ListProviderInstancesWithConfig(ctx context.Conte
resp := ProviderInstanceResponse{ resp := ProviderInstanceResponse{
ID: int64(inst.ID), ProviderKey: inst.ProviderKey, Name: inst.Name, ID: int64(inst.ID), ProviderKey: inst.ProviderKey, Name: inst.Name,
SupportedTypes: splitTypes(inst.SupportedTypes), Limits: inst.Limits, SupportedTypes: splitTypes(inst.SupportedTypes), Limits: inst.Limits,
Enabled: inst.Enabled, RefundEnabled: inst.RefundEnabled, SortOrder: inst.SortOrder, Enabled: inst.Enabled, RefundEnabled: inst.RefundEnabled, AllowUserRefund: inst.AllowUserRefund,
PaymentMode: inst.PaymentMode, SortOrder: inst.SortOrder, PaymentMode: inst.PaymentMode,
} }
resp.Config, err = s.decryptAndMaskConfig(inst.Config) resp.Config, err = s.decryptAndMaskConfig(inst.Config)
if err != nil { if err != nil {
@@ -110,10 +111,12 @@ func (s *PaymentConfigService) CreateProviderInstance(ctx context.Context, req C
if err != nil { if err != nil {
return nil, err return nil, err
} }
allowUserRefund := req.AllowUserRefund && req.RefundEnabled
return s.entClient.PaymentProviderInstance.Create(). return s.entClient.PaymentProviderInstance.Create().
SetProviderKey(req.ProviderKey).SetName(req.Name).SetConfig(enc). SetProviderKey(req.ProviderKey).SetName(req.Name).SetConfig(enc).
SetSupportedTypes(typesStr).SetEnabled(req.Enabled).SetPaymentMode(req.PaymentMode). SetSupportedTypes(typesStr).SetEnabled(req.Enabled).SetPaymentMode(req.PaymentMode).
SetSortOrder(req.SortOrder).SetLimits(req.Limits).SetRefundEnabled(req.RefundEnabled). SetSortOrder(req.SortOrder).SetLimits(req.Limits).SetRefundEnabled(req.RefundEnabled).
SetAllowUserRefund(allowUserRefund).
Save(ctx) Save(ctx)
} }
@@ -221,6 +224,21 @@ func (s *PaymentConfigService) UpdateProviderInstance(ctx context.Context, id in
} }
if req.RefundEnabled != nil { if req.RefundEnabled != nil {
u.SetRefundEnabled(*req.RefundEnabled) u.SetRefundEnabled(*req.RefundEnabled)
// Cascade: turning off refund_enabled also disables allow_user_refund
if !*req.RefundEnabled {
u.SetAllowUserRefund(false)
}
}
if req.AllowUserRefund != nil {
// Only allow enabling when refund_enabled is true
if *req.AllowUserRefund {
inst, err := s.entClient.PaymentProviderInstance.Get(ctx, id)
if err == nil && inst.RefundEnabled {
u.SetAllowUserRefund(true)
}
} else {
u.SetAllowUserRefund(false)
}
} }
if req.PaymentMode != nil { if req.PaymentMode != nil {
u.SetPaymentMode(*req.PaymentMode) u.SetPaymentMode(*req.PaymentMode)
@@ -228,6 +246,23 @@ func (s *PaymentConfigService) UpdateProviderInstance(ctx context.Context, id in
return u.Save(ctx) return u.Save(ctx)
} }
// GetUserRefundEligibleInstanceIDs returns provider instance IDs that allow user refund.
func (s *PaymentConfigService) GetUserRefundEligibleInstanceIDs(ctx context.Context) ([]string, error) {
instances, err := s.entClient.PaymentProviderInstance.Query().
Where(
paymentproviderinstance.AllowUserRefundEQ(true),
paymentproviderinstance.RefundEnabledEQ(true),
).Select(paymentproviderinstance.FieldID).All(ctx)
if err != nil {
return nil, err
}
ids := make([]string, 0, len(instances))
for _, inst := range instances {
ids = append(ids, strconv.FormatInt(int64(inst.ID), 10))
}
return ids, nil
}
func (s *PaymentConfigService) mergeConfig(ctx context.Context, id int64, newConfig map[string]string) (map[string]string, error) { func (s *PaymentConfigService) mergeConfig(ctx context.Context, id int64, newConfig map[string]string) (map[string]string, error) {
inst, err := s.entClient.PaymentProviderInstance.Get(ctx, id) inst, err := s.entClient.PaymentProviderInstance.Get(ctx, id)
if err != nil { if err != nil {

View File

@@ -101,7 +101,7 @@ func TestIsSensitiveConfigField(t *testing.T) {
t.Parallel() t.Parallel()
tests := []struct { tests := []struct {
field string field string
wantSen bool wantSen bool
}{ }{
// Sensitive fields (contain key/secret/private/password/pkey patterns) // Sensitive fields (contain key/secret/private/password/pkey patterns)

View File

@@ -105,26 +105,28 @@ type MethodLimitsResponse struct {
} }
type CreateProviderInstanceRequest struct { type CreateProviderInstanceRequest struct {
ProviderKey string `json:"provider_key"` ProviderKey string `json:"provider_key"`
Name string `json:"name"` Name string `json:"name"`
Config map[string]string `json:"config"` Config map[string]string `json:"config"`
SupportedTypes []string `json:"supported_types"` SupportedTypes []string `json:"supported_types"`
Enabled bool `json:"enabled"` Enabled bool `json:"enabled"`
PaymentMode string `json:"payment_mode"` PaymentMode string `json:"payment_mode"`
SortOrder int `json:"sort_order"` SortOrder int `json:"sort_order"`
Limits string `json:"limits"` Limits string `json:"limits"`
RefundEnabled bool `json:"refund_enabled"` RefundEnabled bool `json:"refund_enabled"`
AllowUserRefund bool `json:"allow_user_refund"`
} }
type UpdateProviderInstanceRequest struct { type UpdateProviderInstanceRequest struct {
Name *string `json:"name"` Name *string `json:"name"`
Config map[string]string `json:"config"` Config map[string]string `json:"config"`
SupportedTypes []string `json:"supported_types"` SupportedTypes []string `json:"supported_types"`
Enabled *bool `json:"enabled"` Enabled *bool `json:"enabled"`
PaymentMode *string `json:"payment_mode"` PaymentMode *string `json:"payment_mode"`
SortOrder *int `json:"sort_order"` SortOrder *int `json:"sort_order"`
Limits *string `json:"limits"` Limits *string `json:"limits"`
RefundEnabled *bool `json:"refund_enabled"` RefundEnabled *bool `json:"refund_enabled"`
AllowUserRefund *bool `json:"allow_user_refund"`
} }
type CreatePlanRequest struct { type CreatePlanRequest struct {
GroupID int64 `json:"group_id"` GroupID int64 `json:"group_id"`

View File

@@ -66,7 +66,7 @@ func TestSettingService_GetPublicSettings_ExposesRegistrationEmailSuffixWhitelis
func TestSettingService_GetPublicSettings_ExposesTablePreferences(t *testing.T) { func TestSettingService_GetPublicSettings_ExposesTablePreferences(t *testing.T) {
repo := &settingPublicRepoStub{ repo := &settingPublicRepoStub{
values: map[string]string{ values: map[string]string{
SettingKeyTableDefaultPageSize: "50", SettingKeyTableDefaultPageSize: "50",
SettingKeyTablePageSizeOptions: "[20,50,100]", SettingKeyTablePageSizeOptions: "[20,50,100]",
}, },
} }

View File

@@ -208,7 +208,7 @@ func TestSettingService_UpdateSettings_TablePreferences(t *testing.T) {
svc := NewSettingService(repo, &config.Config{}) svc := NewSettingService(repo, &config.Config{})
err := svc.UpdateSettings(context.Background(), &SystemSettings{ err := svc.UpdateSettings(context.Background(), &SystemSettings{
TableDefaultPageSize: 50, TableDefaultPageSize: 50,
TablePageSizeOptions: []int{20, 50, 100}, TablePageSizeOptions: []int{20, 50, 100},
}) })
require.NoError(t, err) require.NoError(t, err)
@@ -216,7 +216,7 @@ func TestSettingService_UpdateSettings_TablePreferences(t *testing.T) {
require.Equal(t, "[20,50,100]", repo.updates[SettingKeyTablePageSizeOptions]) require.Equal(t, "[20,50,100]", repo.updates[SettingKeyTablePageSizeOptions])
err = svc.UpdateSettings(context.Background(), &SystemSettings{ err = svc.UpdateSettings(context.Background(), &SystemSettings{
TableDefaultPageSize: 1000, TableDefaultPageSize: 1000,
TablePageSizeOptions: []int{20, 100}, TablePageSizeOptions: []int{20, 100},
}) })
require.NoError(t, err) require.NoError(t, err)

View File

@@ -108,8 +108,8 @@ type SystemSettings struct {
EnableCCHSigning bool // 是否对 billing header cch 进行签名(默认 false EnableCCHSigning bool // 是否对 billing header cch 进行签名(默认 false
// Balance low notification // Balance low notification
BalanceLowNotifyEnabled bool BalanceLowNotifyEnabled bool
BalanceLowNotifyThreshold float64 BalanceLowNotifyThreshold float64
BalanceLowNotifyRechargeURL string BalanceLowNotifyRechargeURL string
// Account quota notification // Account quota notification
@@ -155,10 +155,10 @@ type PublicSettings struct {
OIDCOAuthProviderName string OIDCOAuthProviderName string
Version string Version string
BalanceLowNotifyEnabled bool BalanceLowNotifyEnabled bool
AccountQuotaNotifyEnabled bool AccountQuotaNotifyEnabled bool
BalanceLowNotifyThreshold float64 BalanceLowNotifyThreshold float64
BalanceLowNotifyRechargeURL string BalanceLowNotifyRechargeURL string
} }
// StreamTimeoutSettings 流超时处理配置(仅控制超时后的处理方式,超时判定由网关配置控制) // StreamTimeoutSettings 流超时处理配置(仅控制超时后的处理方式,超时判定由网关配置控制)

View File

@@ -100,9 +100,22 @@ func valueOrZero(v *int64) int64 {
return *v return *v
} }
// AccountQuotaState holds the post-increment quota state returned by the DB transaction.
// All values are post-update (i.e., already include the increment).
type AccountQuotaState struct {
TotalUsed float64
TotalLimit float64
DailyUsed float64
DailyLimit float64
WeeklyUsed float64
WeeklyLimit float64
}
type UsageBillingApplyResult struct { type UsageBillingApplyResult struct {
Applied bool Applied bool
APIKeyQuotaExhausted bool APIKeyQuotaExhausted bool
NewBalance *float64 // post-deduction balance (nil = no balance deduction)
QuotaState *AccountQuotaState // post-increment quota state (nil = no quota increment)
} }
type UsageBillingRepository interface { type UsageBillingRepository interface {

View File

@@ -32,7 +32,7 @@ type User struct {
// 余额不足通知 // 余额不足通知
BalanceNotifyEnabled bool BalanceNotifyEnabled bool
BalanceNotifyThresholdType string // "fixed" (default) | "percentage" BalanceNotifyThresholdType string // "fixed" (default) | "percentage"
BalanceNotifyThreshold *float64 BalanceNotifyThreshold *float64
BalanceNotifyExtraEmails []NotifyEmailEntry BalanceNotifyExtraEmails []NotifyEmailEntry
TotalRecharged float64 TotalRecharged float64

View File

@@ -13,9 +13,9 @@ import (
) )
var ( var (
ErrUserNotFound = infraerrors.NotFound("USER_NOT_FOUND", "user not found") ErrUserNotFound = infraerrors.NotFound("USER_NOT_FOUND", "user not found")
ErrPasswordIncorrect = infraerrors.BadRequest("PASSWORD_INCORRECT", "current password is incorrect") ErrPasswordIncorrect = infraerrors.BadRequest("PASSWORD_INCORRECT", "current password is incorrect")
ErrInsufficientPerms = infraerrors.Forbidden("INSUFFICIENT_PERMISSIONS", "insufficient permissions") ErrInsufficientPerms = infraerrors.Forbidden("INSUFFICIENT_PERMISSIONS", "insufficient permissions")
ErrNotifyCodeUserRateLimit = infraerrors.TooManyRequests("NOTIFY_CODE_USER_RATE_LIMIT", "too many verification codes requested, please try again later") ErrNotifyCodeUserRateLimit = infraerrors.TooManyRequests("NOTIFY_CODE_USER_RATE_LIMIT", "too many verification codes requested, please try again later")
) )