fix settings auth source default persistence
This commit is contained in:
@@ -569,12 +569,47 @@ func parseCustomMenuItemURLs(raw string) []string {
|
||||
|
||||
// UpdateSettings 更新系统设置
|
||||
func (s *SettingService) UpdateSettings(ctx context.Context, settings *SystemSettings) error {
|
||||
if err := s.validateDefaultSubscriptionGroups(ctx, settings.DefaultSubscriptions); err != nil {
|
||||
updates, err := s.buildSystemSettingsUpdates(ctx, settings)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = s.settingRepo.SetMultiple(ctx, updates)
|
||||
if err == nil {
|
||||
s.refreshCachedSettings(settings)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// UpdateSettingsWithAuthSourceDefaults persists system settings and auth-source defaults in a single write.
|
||||
func (s *SettingService) UpdateSettingsWithAuthSourceDefaults(ctx context.Context, settings *SystemSettings, authDefaults *AuthSourceDefaultSettings) error {
|
||||
updates, err := s.buildSystemSettingsUpdates(ctx, settings)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
authSourceUpdates, err := s.buildAuthSourceDefaultUpdates(ctx, authDefaults)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for key, value := range authSourceUpdates {
|
||||
updates[key] = value
|
||||
}
|
||||
|
||||
err = s.settingRepo.SetMultiple(ctx, updates)
|
||||
if err == nil {
|
||||
s.refreshCachedSettings(settings)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *SettingService) buildSystemSettingsUpdates(ctx context.Context, settings *SystemSettings) (map[string]string, error) {
|
||||
if err := s.validateDefaultSubscriptionGroups(ctx, settings.DefaultSubscriptions); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
normalizedWhitelist, err := NormalizeRegistrationEmailSuffixWhitelist(settings.RegistrationEmailSuffixWhitelist)
|
||||
if err != nil {
|
||||
return infraerrors.BadRequest("INVALID_REGISTRATION_EMAIL_SUFFIX_WHITELIST", err.Error())
|
||||
return nil, infraerrors.BadRequest("INVALID_REGISTRATION_EMAIL_SUFFIX_WHITELIST", err.Error())
|
||||
}
|
||||
if normalizedWhitelist == nil {
|
||||
normalizedWhitelist = []string{}
|
||||
@@ -582,11 +617,11 @@ func (s *SettingService) UpdateSettings(ctx context.Context, settings *SystemSet
|
||||
settings.RegistrationEmailSuffixWhitelist = normalizedWhitelist
|
||||
alipaySource, err := normalizeVisibleMethodSettingSource("alipay", settings.PaymentVisibleMethodAlipaySource, settings.PaymentVisibleMethodAlipayEnabled)
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
wxpaySource, err := normalizeVisibleMethodSettingSource("wxpay", settings.PaymentVisibleMethodWxpaySource, settings.PaymentVisibleMethodWxpayEnabled)
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
settings.PaymentVisibleMethodAlipaySource = alipaySource
|
||||
settings.PaymentVisibleMethodWxpaySource = wxpaySource
|
||||
@@ -598,7 +633,7 @@ func (s *SettingService) UpdateSettings(ctx context.Context, settings *SystemSet
|
||||
updates[SettingKeyEmailVerifyEnabled] = strconv.FormatBool(settings.EmailVerifyEnabled)
|
||||
registrationEmailSuffixWhitelistJSON, err := json.Marshal(settings.RegistrationEmailSuffixWhitelist)
|
||||
if err != nil {
|
||||
return fmt.Errorf("marshal registration email suffix whitelist: %w", err)
|
||||
return nil, fmt.Errorf("marshal registration email suffix whitelist: %w", err)
|
||||
}
|
||||
updates[SettingKeyRegistrationEmailSuffixWhitelist] = string(registrationEmailSuffixWhitelistJSON)
|
||||
updates[SettingKeyPromoCodeEnabled] = strconv.FormatBool(settings.PromoCodeEnabled)
|
||||
@@ -677,7 +712,7 @@ func (s *SettingService) UpdateSettings(ctx context.Context, settings *SystemSet
|
||||
updates[SettingKeyTableDefaultPageSize] = strconv.Itoa(tableDefaultPageSize)
|
||||
tablePageSizeOptionsJSON, err := json.Marshal(tablePageSizeOptions)
|
||||
if err != nil {
|
||||
return fmt.Errorf("marshal table page size options: %w", err)
|
||||
return nil, fmt.Errorf("marshal table page size options: %w", err)
|
||||
}
|
||||
updates[SettingKeyTablePageSizeOptions] = string(tablePageSizeOptionsJSON)
|
||||
updates[SettingKeyCustomMenuItems] = settings.CustomMenuItems
|
||||
@@ -688,7 +723,7 @@ func (s *SettingService) UpdateSettings(ctx context.Context, settings *SystemSet
|
||||
updates[SettingKeyDefaultBalance] = strconv.FormatFloat(settings.DefaultBalance, 'f', 8, 64)
|
||||
defaultSubsJSON, err := json.Marshal(settings.DefaultSubscriptions)
|
||||
if err != nil {
|
||||
return fmt.Errorf("marshal default subscriptions: %w", err)
|
||||
return nil, fmt.Errorf("marshal default subscriptions: %w", err)
|
||||
}
|
||||
updates[SettingKeyDefaultSubscriptions] = string(defaultSubsJSON)
|
||||
|
||||
@@ -738,37 +773,66 @@ func (s *SettingService) UpdateSettings(ctx context.Context, settings *SystemSet
|
||||
updates[SettingKeyAccountQuotaNotifyEnabled] = strconv.FormatBool(settings.AccountQuotaNotifyEnabled)
|
||||
updates[SettingKeyAccountQuotaNotifyEmails] = MarshalNotifyEmails(settings.AccountQuotaNotifyEmails)
|
||||
|
||||
err = s.settingRepo.SetMultiple(ctx, updates)
|
||||
if err == nil {
|
||||
// 先使 inflight singleflight 失效,再刷新缓存,缩小旧值覆盖新值的竞态窗口
|
||||
versionBoundsSF.Forget("version_bounds")
|
||||
versionBoundsCache.Store(&cachedVersionBounds{
|
||||
min: settings.MinClaudeCodeVersion,
|
||||
max: settings.MaxClaudeCodeVersion,
|
||||
expiresAt: time.Now().Add(versionBoundsCacheTTL).UnixNano(),
|
||||
})
|
||||
backendModeSF.Forget("backend_mode")
|
||||
backendModeCache.Store(&cachedBackendMode{
|
||||
value: settings.BackendModeEnabled,
|
||||
expiresAt: time.Now().Add(backendModeCacheTTL).UnixNano(),
|
||||
})
|
||||
gatewayForwardingSF.Forget("gateway_forwarding")
|
||||
gatewayForwardingCache.Store(&cachedGatewayForwardingSettings{
|
||||
fingerprintUnification: settings.EnableFingerprintUnification,
|
||||
metadataPassthrough: settings.EnableMetadataPassthrough,
|
||||
cchSigning: settings.EnableCCHSigning,
|
||||
expiresAt: time.Now().Add(gatewayForwardingCacheTTL).UnixNano(),
|
||||
})
|
||||
openAIAdvancedSchedulerSettingSF.Forget(openAIAdvancedSchedulerSettingKey)
|
||||
openAIAdvancedSchedulerSettingCache.Store(&cachedOpenAIAdvancedSchedulerSetting{
|
||||
enabled: settings.OpenAIAdvancedSchedulerEnabled,
|
||||
expiresAt: time.Now().Add(openAIAdvancedSchedulerSettingCacheTTL).UnixNano(),
|
||||
})
|
||||
if s.onUpdate != nil {
|
||||
s.onUpdate() // Invalidate cache after settings update
|
||||
return updates, nil
|
||||
}
|
||||
|
||||
func (s *SettingService) buildAuthSourceDefaultUpdates(ctx context.Context, settings *AuthSourceDefaultSettings) (map[string]string, error) {
|
||||
if settings == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
for _, subscriptions := range [][]DefaultSubscriptionSetting{
|
||||
settings.Email.Subscriptions,
|
||||
settings.LinuxDo.Subscriptions,
|
||||
settings.OIDC.Subscriptions,
|
||||
settings.WeChat.Subscriptions,
|
||||
} {
|
||||
if err := s.validateDefaultSubscriptionGroups(ctx, subscriptions); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return err
|
||||
|
||||
updates := make(map[string]string, 21)
|
||||
writeProviderDefaultGrantUpdates(updates, emailAuthSourceDefaultKeys, settings.Email)
|
||||
writeProviderDefaultGrantUpdates(updates, linuxDoAuthSourceDefaultKeys, settings.LinuxDo)
|
||||
writeProviderDefaultGrantUpdates(updates, oidcAuthSourceDefaultKeys, settings.OIDC)
|
||||
writeProviderDefaultGrantUpdates(updates, weChatAuthSourceDefaultKeys, settings.WeChat)
|
||||
updates[SettingKeyForceEmailOnThirdPartySignup] = strconv.FormatBool(settings.ForceEmailOnThirdPartySignup)
|
||||
return updates, nil
|
||||
}
|
||||
|
||||
func (s *SettingService) refreshCachedSettings(settings *SystemSettings) {
|
||||
if settings == nil {
|
||||
return
|
||||
}
|
||||
|
||||
// 先使 inflight singleflight 失效,再刷新缓存,缩小旧值覆盖新值的竞态窗口
|
||||
versionBoundsSF.Forget("version_bounds")
|
||||
versionBoundsCache.Store(&cachedVersionBounds{
|
||||
min: settings.MinClaudeCodeVersion,
|
||||
max: settings.MaxClaudeCodeVersion,
|
||||
expiresAt: time.Now().Add(versionBoundsCacheTTL).UnixNano(),
|
||||
})
|
||||
backendModeSF.Forget("backend_mode")
|
||||
backendModeCache.Store(&cachedBackendMode{
|
||||
value: settings.BackendModeEnabled,
|
||||
expiresAt: time.Now().Add(backendModeCacheTTL).UnixNano(),
|
||||
})
|
||||
gatewayForwardingSF.Forget("gateway_forwarding")
|
||||
gatewayForwardingCache.Store(&cachedGatewayForwardingSettings{
|
||||
fingerprintUnification: settings.EnableFingerprintUnification,
|
||||
metadataPassthrough: settings.EnableMetadataPassthrough,
|
||||
cchSigning: settings.EnableCCHSigning,
|
||||
expiresAt: time.Now().Add(gatewayForwardingCacheTTL).UnixNano(),
|
||||
})
|
||||
openAIAdvancedSchedulerSettingSF.Forget(openAIAdvancedSchedulerSettingKey)
|
||||
openAIAdvancedSchedulerSettingCache.Store(&cachedOpenAIAdvancedSchedulerSetting{
|
||||
enabled: settings.OpenAIAdvancedSchedulerEnabled,
|
||||
expiresAt: time.Now().Add(openAIAdvancedSchedulerSettingCacheTTL).UnixNano(),
|
||||
})
|
||||
if s.onUpdate != nil {
|
||||
s.onUpdate() // Invalidate cache after settings update
|
||||
}
|
||||
}
|
||||
|
||||
func (s *SettingService) validateDefaultSubscriptionGroups(ctx context.Context, items []DefaultSubscriptionSetting) error {
|
||||
@@ -1067,29 +1131,43 @@ func (s *SettingService) GetAuthSourceDefaultSettings(ctx context.Context) (*Aut
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *SettingService) ResolveAuthSourceGrantSettings(ctx context.Context, signupSource string, firstBind bool) (ProviderDefaultGrantSettings, bool, error) {
|
||||
result := ProviderDefaultGrantSettings{
|
||||
Balance: s.GetDefaultBalance(ctx),
|
||||
Concurrency: s.GetDefaultConcurrency(ctx),
|
||||
Subscriptions: s.GetDefaultSubscriptions(ctx),
|
||||
}
|
||||
|
||||
defaults, err := s.GetAuthSourceDefaultSettings(ctx)
|
||||
if err != nil {
|
||||
return result, false, err
|
||||
}
|
||||
|
||||
providerDefaults, ok := authSourceSignupSettings(defaults, signupSource)
|
||||
if !ok {
|
||||
return result, false, nil
|
||||
}
|
||||
|
||||
enabled := providerDefaults.GrantOnSignup
|
||||
if firstBind {
|
||||
enabled = providerDefaults.GrantOnFirstBind
|
||||
}
|
||||
if !enabled {
|
||||
return result, false, nil
|
||||
}
|
||||
|
||||
return mergeProviderDefaultGrantSettings(result, providerDefaults), true, nil
|
||||
}
|
||||
|
||||
func (s *SettingService) UpdateAuthSourceDefaultSettings(ctx context.Context, settings *AuthSourceDefaultSettings) error {
|
||||
if settings == nil {
|
||||
updates, err := s.buildAuthSourceDefaultUpdates(ctx, settings)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(updates) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
for _, subscriptions := range [][]DefaultSubscriptionSetting{
|
||||
settings.Email.Subscriptions,
|
||||
settings.LinuxDo.Subscriptions,
|
||||
settings.OIDC.Subscriptions,
|
||||
settings.WeChat.Subscriptions,
|
||||
} {
|
||||
if err := s.validateDefaultSubscriptionGroups(ctx, subscriptions); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
updates := make(map[string]string, 21)
|
||||
writeProviderDefaultGrantUpdates(updates, emailAuthSourceDefaultKeys, settings.Email)
|
||||
writeProviderDefaultGrantUpdates(updates, linuxDoAuthSourceDefaultKeys, settings.LinuxDo)
|
||||
writeProviderDefaultGrantUpdates(updates, oidcAuthSourceDefaultKeys, settings.OIDC)
|
||||
writeProviderDefaultGrantUpdates(updates, weChatAuthSourceDefaultKeys, settings.WeChat)
|
||||
updates[SettingKeyForceEmailOnThirdPartySignup] = strconv.FormatBool(settings.ForceEmailOnThirdPartySignup)
|
||||
|
||||
if err := s.settingRepo.SetMultiple(ctx, updates); err != nil {
|
||||
return fmt.Errorf("update auth source default settings: %w", err)
|
||||
}
|
||||
@@ -1594,6 +1672,28 @@ func writeProviderDefaultGrantUpdates(updates map[string]string, keys authSource
|
||||
updates[keys.grantOnFirstBind] = strconv.FormatBool(settings.GrantOnFirstBind)
|
||||
}
|
||||
|
||||
func mergeProviderDefaultGrantSettings(globalDefaults ProviderDefaultGrantSettings, providerDefaults ProviderDefaultGrantSettings) ProviderDefaultGrantSettings {
|
||||
result := ProviderDefaultGrantSettings{
|
||||
Balance: globalDefaults.Balance,
|
||||
Concurrency: globalDefaults.Concurrency,
|
||||
Subscriptions: append([]DefaultSubscriptionSetting(nil), globalDefaults.Subscriptions...),
|
||||
GrantOnSignup: providerDefaults.GrantOnSignup,
|
||||
GrantOnFirstBind: providerDefaults.GrantOnFirstBind,
|
||||
}
|
||||
|
||||
if providerDefaults.Balance != defaultAuthSourceBalance {
|
||||
result.Balance = providerDefaults.Balance
|
||||
}
|
||||
if providerDefaults.Concurrency > 0 && providerDefaults.Concurrency != defaultAuthSourceConcurrency {
|
||||
result.Concurrency = providerDefaults.Concurrency
|
||||
}
|
||||
if len(providerDefaults.Subscriptions) > 0 {
|
||||
result.Subscriptions = append([]DefaultSubscriptionSetting(nil), providerDefaults.Subscriptions...)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func parseTablePreferences(defaultPageSizeRaw, optionsRaw string) (int, []int) {
|
||||
defaultPageSize := 20
|
||||
if v, err := strconv.Atoi(strings.TrimSpace(defaultPageSizeRaw)); err == nil {
|
||||
|
||||
Reference in New Issue
Block a user