fix(settings): restore wechat and payment config persistence
This commit is contained in:
@@ -9,7 +9,6 @@ import (
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"net/url"
|
||||
"os"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
@@ -173,8 +172,43 @@ var (
|
||||
const (
|
||||
defaultAuthSourceBalance = 0
|
||||
defaultAuthSourceConcurrency = 5
|
||||
defaultWeChatConnectMode = "open"
|
||||
defaultWeChatConnectScopes = "snsapi_login"
|
||||
defaultWeChatConnectFrontend = "/auth/wechat/callback"
|
||||
)
|
||||
|
||||
func normalizeWeChatConnectModeSetting(raw string) string {
|
||||
switch strings.ToLower(strings.TrimSpace(raw)) {
|
||||
case "mp":
|
||||
return "mp"
|
||||
default:
|
||||
return "open"
|
||||
}
|
||||
}
|
||||
|
||||
func defaultWeChatConnectScopeForMode(mode string) string {
|
||||
if normalizeWeChatConnectModeSetting(mode) == "mp" {
|
||||
return "snsapi_userinfo"
|
||||
}
|
||||
return defaultWeChatConnectScopes
|
||||
}
|
||||
|
||||
func normalizeWeChatConnectScopeSetting(raw, mode string) string {
|
||||
switch normalizeWeChatConnectModeSetting(mode) {
|
||||
case "mp":
|
||||
switch strings.TrimSpace(raw) {
|
||||
case "snsapi_base":
|
||||
return "snsapi_base"
|
||||
case "snsapi_userinfo":
|
||||
return "snsapi_userinfo"
|
||||
default:
|
||||
return defaultWeChatConnectScopeForMode(mode)
|
||||
}
|
||||
default:
|
||||
return defaultWeChatConnectScopes
|
||||
}
|
||||
}
|
||||
|
||||
// NewSettingService 创建系统设置服务实例
|
||||
func NewSettingService(settingRepo SettingRepository, cfg *config.Config) *SettingService {
|
||||
return &SettingService{
|
||||
@@ -240,6 +274,13 @@ func (s *SettingService) GetPublicSettings(ctx context.Context) (*PublicSettings
|
||||
SettingKeyCustomMenuItems,
|
||||
SettingKeyCustomEndpoints,
|
||||
SettingKeyLinuxDoConnectEnabled,
|
||||
SettingKeyWeChatConnectEnabled,
|
||||
SettingKeyWeChatConnectAppID,
|
||||
SettingKeyWeChatConnectAppSecret,
|
||||
SettingKeyWeChatConnectMode,
|
||||
SettingKeyWeChatConnectScopes,
|
||||
SettingKeyWeChatConnectRedirectURL,
|
||||
SettingKeyWeChatConnectFrontendRedirectURL,
|
||||
SettingKeyBackendModeEnabled,
|
||||
SettingPaymentEnabled,
|
||||
SettingKeyOIDCConnectEnabled,
|
||||
@@ -274,9 +315,7 @@ func (s *SettingService) GetPublicSettings(ctx context.Context) (*PublicSettings
|
||||
if oidcProviderName == "" {
|
||||
oidcProviderName = "OIDC"
|
||||
}
|
||||
weChatOpenEnabled := isWeChatOAuthOpenConfigured()
|
||||
weChatMPEnabled := isWeChatOAuthMPConfigured()
|
||||
weChatEnabled := weChatOpenEnabled || weChatMPEnabled
|
||||
weChatEnabled, weChatOpenEnabled, weChatMPEnabled := s.weChatOAuthCapabilitiesFromSettings(settings)
|
||||
|
||||
// Password reset requires email verification to be enabled
|
||||
emailVerifyEnabled := settings[SettingKeyEmailVerifyEnabled] == "true"
|
||||
@@ -431,6 +470,56 @@ func (s *SettingService) GetPublicSettingsForInjection(ctx context.Context) (any
|
||||
}, nil
|
||||
}
|
||||
|
||||
func DefaultWeChatConnectScopesForMode(mode string) string {
|
||||
return defaultWeChatConnectScopeForMode(mode)
|
||||
}
|
||||
|
||||
func (s *SettingService) parseWeChatConnectOAuthConfig(settings map[string]string) (WeChatConnectOAuthConfig, error) {
|
||||
cfg := WeChatConnectOAuthConfig{
|
||||
Enabled: settings[SettingKeyWeChatConnectEnabled] == "true",
|
||||
AppID: strings.TrimSpace(settings[SettingKeyWeChatConnectAppID]),
|
||||
AppSecret: strings.TrimSpace(settings[SettingKeyWeChatConnectAppSecret]),
|
||||
Mode: normalizeWeChatConnectModeSetting(settings[SettingKeyWeChatConnectMode]),
|
||||
Scopes: normalizeWeChatConnectScopeSetting(settings[SettingKeyWeChatConnectScopes], settings[SettingKeyWeChatConnectMode]),
|
||||
RedirectURL: strings.TrimSpace(settings[SettingKeyWeChatConnectRedirectURL]),
|
||||
FrontendRedirectURL: strings.TrimSpace(settings[SettingKeyWeChatConnectFrontendRedirectURL]),
|
||||
}
|
||||
if cfg.FrontendRedirectURL == "" {
|
||||
cfg.FrontendRedirectURL = defaultWeChatConnectFrontend
|
||||
}
|
||||
|
||||
if !cfg.Enabled {
|
||||
return WeChatConnectOAuthConfig{}, infraerrors.NotFound("OAUTH_DISABLED", "wechat oauth is disabled")
|
||||
}
|
||||
if cfg.AppID == "" {
|
||||
return WeChatConnectOAuthConfig{}, infraerrors.InternalServer("OAUTH_CONFIG_INVALID", "wechat oauth app id not configured")
|
||||
}
|
||||
if cfg.AppSecret == "" {
|
||||
return WeChatConnectOAuthConfig{}, infraerrors.InternalServer("OAUTH_CONFIG_INVALID", "wechat oauth app secret not configured")
|
||||
}
|
||||
if cfg.RedirectURL == "" {
|
||||
return WeChatConnectOAuthConfig{}, infraerrors.InternalServer("OAUTH_CONFIG_INVALID", "wechat oauth redirect url not configured")
|
||||
}
|
||||
if cfg.FrontendRedirectURL == "" {
|
||||
return WeChatConnectOAuthConfig{}, infraerrors.InternalServer("OAUTH_CONFIG_INVALID", "wechat oauth frontend redirect url not configured")
|
||||
}
|
||||
if err := config.ValidateAbsoluteHTTPURL(cfg.RedirectURL); err != nil {
|
||||
return WeChatConnectOAuthConfig{}, infraerrors.InternalServer("OAUTH_CONFIG_INVALID", "wechat oauth redirect url invalid")
|
||||
}
|
||||
if err := config.ValidateFrontendRedirectURL(cfg.FrontendRedirectURL); err != nil {
|
||||
return WeChatConnectOAuthConfig{}, infraerrors.InternalServer("OAUTH_CONFIG_INVALID", "wechat oauth frontend redirect url invalid")
|
||||
}
|
||||
return cfg, nil
|
||||
}
|
||||
|
||||
func (s *SettingService) weChatOAuthCapabilitiesFromSettings(settings map[string]string) (bool, bool, bool) {
|
||||
cfg, err := s.parseWeChatConnectOAuthConfig(settings)
|
||||
if err != nil {
|
||||
return false, false, false
|
||||
}
|
||||
return true, cfg.Mode == "open", cfg.Mode == "mp"
|
||||
}
|
||||
|
||||
// filterUserVisibleMenuItems filters out admin-only menu items from a raw JSON
|
||||
// array string, returning only items with visibility != "admin".
|
||||
func filterUserVisibleMenuItems(raw string) json.RawMessage {
|
||||
@@ -467,20 +556,6 @@ func filterUserVisibleMenuItems(raw string) json.RawMessage {
|
||||
return result
|
||||
}
|
||||
|
||||
func isWeChatOAuthConfigured() bool {
|
||||
return isWeChatOAuthOpenConfigured() || isWeChatOAuthMPConfigured()
|
||||
}
|
||||
|
||||
func isWeChatOAuthOpenConfigured() bool {
|
||||
return strings.TrimSpace(os.Getenv("WECHAT_OAUTH_OPEN_APP_ID")) != "" &&
|
||||
strings.TrimSpace(os.Getenv("WECHAT_OAUTH_OPEN_APP_SECRET")) != ""
|
||||
}
|
||||
|
||||
func isWeChatOAuthMPConfigured() bool {
|
||||
return strings.TrimSpace(os.Getenv("WECHAT_OAUTH_MP_APP_ID")) != "" &&
|
||||
strings.TrimSpace(os.Getenv("WECHAT_OAUTH_MP_APP_SECRET")) != ""
|
||||
}
|
||||
|
||||
// safeRawJSONArray returns raw as json.RawMessage if it's valid JSON, otherwise "[]".
|
||||
func safeRawJSONArray(raw string) json.RawMessage {
|
||||
raw = strings.TrimSpace(raw)
|
||||
@@ -625,6 +700,15 @@ func (s *SettingService) buildSystemSettingsUpdates(ctx context.Context, setting
|
||||
}
|
||||
settings.PaymentVisibleMethodAlipaySource = alipaySource
|
||||
settings.PaymentVisibleMethodWxpaySource = wxpaySource
|
||||
settings.WeChatConnectAppID = strings.TrimSpace(settings.WeChatConnectAppID)
|
||||
settings.WeChatConnectAppSecret = strings.TrimSpace(settings.WeChatConnectAppSecret)
|
||||
settings.WeChatConnectMode = normalizeWeChatConnectModeSetting(settings.WeChatConnectMode)
|
||||
settings.WeChatConnectScopes = normalizeWeChatConnectScopeSetting(settings.WeChatConnectScopes, settings.WeChatConnectMode)
|
||||
settings.WeChatConnectRedirectURL = strings.TrimSpace(settings.WeChatConnectRedirectURL)
|
||||
settings.WeChatConnectFrontendRedirectURL = strings.TrimSpace(settings.WeChatConnectFrontendRedirectURL)
|
||||
if settings.WeChatConnectFrontendRedirectURL == "" {
|
||||
settings.WeChatConnectFrontendRedirectURL = defaultWeChatConnectFrontend
|
||||
}
|
||||
|
||||
updates := make(map[string]string)
|
||||
|
||||
@@ -694,6 +778,17 @@ func (s *SettingService) buildSystemSettingsUpdates(ctx context.Context, setting
|
||||
updates[SettingKeyOIDCConnectClientSecret] = settings.OIDCConnectClientSecret
|
||||
}
|
||||
|
||||
// WeChat Connect OAuth 登录
|
||||
updates[SettingKeyWeChatConnectEnabled] = strconv.FormatBool(settings.WeChatConnectEnabled)
|
||||
updates[SettingKeyWeChatConnectAppID] = settings.WeChatConnectAppID
|
||||
updates[SettingKeyWeChatConnectMode] = settings.WeChatConnectMode
|
||||
updates[SettingKeyWeChatConnectScopes] = settings.WeChatConnectScopes
|
||||
updates[SettingKeyWeChatConnectRedirectURL] = settings.WeChatConnectRedirectURL
|
||||
updates[SettingKeyWeChatConnectFrontendRedirectURL] = settings.WeChatConnectFrontendRedirectURL
|
||||
if settings.WeChatConnectAppSecret != "" {
|
||||
updates[SettingKeyWeChatConnectAppSecret] = settings.WeChatConnectAppSecret
|
||||
}
|
||||
|
||||
// OEM设置
|
||||
updates[SettingKeySiteName] = settings.SiteName
|
||||
updates[SettingKeySiteLogo] = settings.SiteLogo
|
||||
@@ -1200,6 +1295,10 @@ func (s *SettingService) InitializeDefaultSettings(ctx context.Context) error {
|
||||
SettingKeyTablePageSizeOptions: "[10,20,50,100]",
|
||||
SettingKeyCustomMenuItems: "[]",
|
||||
SettingKeyCustomEndpoints: "[]",
|
||||
SettingKeyWeChatConnectEnabled: "false",
|
||||
SettingKeyWeChatConnectMode: "open",
|
||||
SettingKeyWeChatConnectScopes: "snsapi_login",
|
||||
SettingKeyWeChatConnectFrontendRedirectURL: defaultWeChatConnectFrontend,
|
||||
SettingKeyOIDCConnectEnabled: "false",
|
||||
SettingKeyOIDCConnectProviderName: "OIDC",
|
||||
SettingKeyDefaultConcurrency: strconv.Itoa(s.cfg.Default.UserConcurrency),
|
||||
@@ -1491,6 +1590,19 @@ func (s *SettingService) parseSettings(settings map[string]string) *SystemSettin
|
||||
}
|
||||
result.OIDCConnectClientSecretConfigured = result.OIDCConnectClientSecret != ""
|
||||
|
||||
// WeChat Connect 设置:完全以 DB 系统设置为准。
|
||||
result.WeChatConnectEnabled = settings[SettingKeyWeChatConnectEnabled] == "true"
|
||||
result.WeChatConnectAppID = strings.TrimSpace(settings[SettingKeyWeChatConnectAppID])
|
||||
result.WeChatConnectAppSecret = strings.TrimSpace(settings[SettingKeyWeChatConnectAppSecret])
|
||||
result.WeChatConnectAppSecretConfigured = result.WeChatConnectAppSecret != ""
|
||||
result.WeChatConnectMode = normalizeWeChatConnectModeSetting(settings[SettingKeyWeChatConnectMode])
|
||||
result.WeChatConnectScopes = normalizeWeChatConnectScopeSetting(settings[SettingKeyWeChatConnectScopes], settings[SettingKeyWeChatConnectMode])
|
||||
result.WeChatConnectRedirectURL = strings.TrimSpace(settings[SettingKeyWeChatConnectRedirectURL])
|
||||
result.WeChatConnectFrontendRedirectURL = strings.TrimSpace(settings[SettingKeyWeChatConnectFrontendRedirectURL])
|
||||
if result.WeChatConnectFrontendRedirectURL == "" {
|
||||
result.WeChatConnectFrontendRedirectURL = defaultWeChatConnectFrontend
|
||||
}
|
||||
|
||||
// Model fallback settings
|
||||
result.EnableModelFallback = settings[SettingKeyEnableModelFallback] == "true"
|
||||
result.FallbackModelAnthropic = s.getStringOrDefault(settings, SettingKeyFallbackModelAnthropic, "claude-3-5-sonnet-20241022")
|
||||
@@ -1972,6 +2084,26 @@ func (s *SettingService) GetLinuxDoConnectOAuthConfig(ctx context.Context) (conf
|
||||
return effective, nil
|
||||
}
|
||||
|
||||
// GetWeChatConnectOAuthConfig 返回用于登录的最终生效 WeChat Connect 配置。
|
||||
//
|
||||
// WeChat Connect 已回归 DB 系统设置模型,不再回退到 config/env。
|
||||
func (s *SettingService) GetWeChatConnectOAuthConfig(ctx context.Context) (WeChatConnectOAuthConfig, error) {
|
||||
keys := []string{
|
||||
SettingKeyWeChatConnectEnabled,
|
||||
SettingKeyWeChatConnectAppID,
|
||||
SettingKeyWeChatConnectAppSecret,
|
||||
SettingKeyWeChatConnectMode,
|
||||
SettingKeyWeChatConnectScopes,
|
||||
SettingKeyWeChatConnectRedirectURL,
|
||||
SettingKeyWeChatConnectFrontendRedirectURL,
|
||||
}
|
||||
settings, err := s.settingRepo.GetMultiple(ctx, keys)
|
||||
if err != nil {
|
||||
return WeChatConnectOAuthConfig{}, fmt.Errorf("get wechat connect settings: %w", err)
|
||||
}
|
||||
return s.parseWeChatConnectOAuthConfig(settings)
|
||||
}
|
||||
|
||||
// GetOverloadCooldownSettings 获取529过载冷却配置
|
||||
func (s *SettingService) GetOverloadCooldownSettings(ctx context.Context) (*OverloadCooldownSettings, error) {
|
||||
value, err := s.settingRepo.GetValue(ctx, SettingKeyOverloadCooldownSettings)
|
||||
|
||||
Reference in New Issue
Block a user