feat(settings): support dual-mode wechat oauth defaults
This commit is contained in:
@@ -125,6 +125,8 @@ func (h *SettingHandler) GetSettings(c *gin.Context) {
|
|||||||
WeChatConnectEnabled: settings.WeChatConnectEnabled,
|
WeChatConnectEnabled: settings.WeChatConnectEnabled,
|
||||||
WeChatConnectAppID: settings.WeChatConnectAppID,
|
WeChatConnectAppID: settings.WeChatConnectAppID,
|
||||||
WeChatConnectAppSecretConfigured: settings.WeChatConnectAppSecretConfigured,
|
WeChatConnectAppSecretConfigured: settings.WeChatConnectAppSecretConfigured,
|
||||||
|
WeChatConnectOpenEnabled: settings.WeChatConnectOpenEnabled,
|
||||||
|
WeChatConnectMPEnabled: settings.WeChatConnectMPEnabled,
|
||||||
WeChatConnectMode: settings.WeChatConnectMode,
|
WeChatConnectMode: settings.WeChatConnectMode,
|
||||||
WeChatConnectScopes: settings.WeChatConnectScopes,
|
WeChatConnectScopes: settings.WeChatConnectScopes,
|
||||||
WeChatConnectRedirectURL: settings.WeChatConnectRedirectURL,
|
WeChatConnectRedirectURL: settings.WeChatConnectRedirectURL,
|
||||||
@@ -257,6 +259,8 @@ type UpdateSettingsRequest struct {
|
|||||||
WeChatConnectEnabled bool `json:"wechat_connect_enabled"`
|
WeChatConnectEnabled bool `json:"wechat_connect_enabled"`
|
||||||
WeChatConnectAppID string `json:"wechat_connect_app_id"`
|
WeChatConnectAppID string `json:"wechat_connect_app_id"`
|
||||||
WeChatConnectAppSecret string `json:"wechat_connect_app_secret"`
|
WeChatConnectAppSecret string `json:"wechat_connect_app_secret"`
|
||||||
|
WeChatConnectOpenEnabled bool `json:"wechat_connect_open_enabled"`
|
||||||
|
WeChatConnectMPEnabled bool `json:"wechat_connect_mp_enabled"`
|
||||||
WeChatConnectMode string `json:"wechat_connect_mode"`
|
WeChatConnectMode string `json:"wechat_connect_mode"`
|
||||||
WeChatConnectScopes string `json:"wechat_connect_scopes"`
|
WeChatConnectScopes string `json:"wechat_connect_scopes"`
|
||||||
WeChatConnectRedirectURL string `json:"wechat_connect_redirect_url"`
|
WeChatConnectRedirectURL string `json:"wechat_connect_redirect_url"`
|
||||||
@@ -544,18 +548,36 @@ func (h *SettingHandler) UpdateSettings(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
req.WeChatConnectAppSecret = previousSettings.WeChatConnectAppSecret
|
req.WeChatConnectAppSecret = previousSettings.WeChatConnectAppSecret
|
||||||
}
|
}
|
||||||
if req.WeChatConnectMode == "" {
|
if req.WeChatConnectMode != "" {
|
||||||
req.WeChatConnectMode = "open"
|
|
||||||
}
|
|
||||||
switch req.WeChatConnectMode {
|
switch req.WeChatConnectMode {
|
||||||
case "open", "mp":
|
case "open", "mp":
|
||||||
default:
|
default:
|
||||||
response.BadRequest(c, "WeChat mode must be open or mp")
|
response.BadRequest(c, "WeChat mode must be open or mp")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
if !req.WeChatConnectOpenEnabled && !req.WeChatConnectMPEnabled {
|
||||||
|
switch req.WeChatConnectMode {
|
||||||
|
case "mp":
|
||||||
|
req.WeChatConnectMPEnabled = true
|
||||||
|
default:
|
||||||
|
req.WeChatConnectOpenEnabled = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if req.WeChatConnectMode == "" {
|
||||||
|
if req.WeChatConnectMPEnabled {
|
||||||
|
req.WeChatConnectMode = "mp"
|
||||||
|
} else {
|
||||||
|
req.WeChatConnectMode = "open"
|
||||||
|
}
|
||||||
|
}
|
||||||
if req.WeChatConnectScopes == "" {
|
if req.WeChatConnectScopes == "" {
|
||||||
|
if req.WeChatConnectMPEnabled {
|
||||||
|
req.WeChatConnectScopes = service.DefaultWeChatConnectScopesForMode("mp")
|
||||||
|
} else {
|
||||||
req.WeChatConnectScopes = service.DefaultWeChatConnectScopesForMode(req.WeChatConnectMode)
|
req.WeChatConnectScopes = service.DefaultWeChatConnectScopesForMode(req.WeChatConnectMode)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if req.WeChatConnectRedirectURL == "" {
|
if req.WeChatConnectRedirectURL == "" {
|
||||||
response.BadRequest(c, "WeChat Redirect URL is required when enabled")
|
response.BadRequest(c, "WeChat Redirect URL is required when enabled")
|
||||||
return
|
return
|
||||||
@@ -924,6 +946,8 @@ func (h *SettingHandler) UpdateSettings(c *gin.Context) {
|
|||||||
WeChatConnectEnabled: req.WeChatConnectEnabled,
|
WeChatConnectEnabled: req.WeChatConnectEnabled,
|
||||||
WeChatConnectAppID: req.WeChatConnectAppID,
|
WeChatConnectAppID: req.WeChatConnectAppID,
|
||||||
WeChatConnectAppSecret: req.WeChatConnectAppSecret,
|
WeChatConnectAppSecret: req.WeChatConnectAppSecret,
|
||||||
|
WeChatConnectOpenEnabled: req.WeChatConnectOpenEnabled,
|
||||||
|
WeChatConnectMPEnabled: req.WeChatConnectMPEnabled,
|
||||||
WeChatConnectMode: req.WeChatConnectMode,
|
WeChatConnectMode: req.WeChatConnectMode,
|
||||||
WeChatConnectScopes: req.WeChatConnectScopes,
|
WeChatConnectScopes: req.WeChatConnectScopes,
|
||||||
WeChatConnectRedirectURL: req.WeChatConnectRedirectURL,
|
WeChatConnectRedirectURL: req.WeChatConnectRedirectURL,
|
||||||
@@ -1210,6 +1234,8 @@ func (h *SettingHandler) UpdateSettings(c *gin.Context) {
|
|||||||
WeChatConnectEnabled: updatedSettings.WeChatConnectEnabled,
|
WeChatConnectEnabled: updatedSettings.WeChatConnectEnabled,
|
||||||
WeChatConnectAppID: updatedSettings.WeChatConnectAppID,
|
WeChatConnectAppID: updatedSettings.WeChatConnectAppID,
|
||||||
WeChatConnectAppSecretConfigured: updatedSettings.WeChatConnectAppSecretConfigured,
|
WeChatConnectAppSecretConfigured: updatedSettings.WeChatConnectAppSecretConfigured,
|
||||||
|
WeChatConnectOpenEnabled: updatedSettings.WeChatConnectOpenEnabled,
|
||||||
|
WeChatConnectMPEnabled: updatedSettings.WeChatConnectMPEnabled,
|
||||||
WeChatConnectMode: updatedSettings.WeChatConnectMode,
|
WeChatConnectMode: updatedSettings.WeChatConnectMode,
|
||||||
WeChatConnectScopes: updatedSettings.WeChatConnectScopes,
|
WeChatConnectScopes: updatedSettings.WeChatConnectScopes,
|
||||||
WeChatConnectRedirectURL: updatedSettings.WeChatConnectRedirectURL,
|
WeChatConnectRedirectURL: updatedSettings.WeChatConnectRedirectURL,
|
||||||
@@ -1416,6 +1442,12 @@ func diffSettings(before *service.SystemSettings, after *service.SystemSettings,
|
|||||||
if req.WeChatConnectAppSecret != "" {
|
if req.WeChatConnectAppSecret != "" {
|
||||||
changed = append(changed, "wechat_connect_app_secret")
|
changed = append(changed, "wechat_connect_app_secret")
|
||||||
}
|
}
|
||||||
|
if before.WeChatConnectOpenEnabled != after.WeChatConnectOpenEnabled {
|
||||||
|
changed = append(changed, "wechat_connect_open_enabled")
|
||||||
|
}
|
||||||
|
if before.WeChatConnectMPEnabled != after.WeChatConnectMPEnabled {
|
||||||
|
changed = append(changed, "wechat_connect_mp_enabled")
|
||||||
|
}
|
||||||
if before.WeChatConnectMode != after.WeChatConnectMode {
|
if before.WeChatConnectMode != after.WeChatConnectMode {
|
||||||
changed = append(changed, "wechat_connect_mode")
|
changed = append(changed, "wechat_connect_mode")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,6 +54,8 @@ type SystemSettings struct {
|
|||||||
WeChatConnectEnabled bool `json:"wechat_connect_enabled"`
|
WeChatConnectEnabled bool `json:"wechat_connect_enabled"`
|
||||||
WeChatConnectAppID string `json:"wechat_connect_app_id"`
|
WeChatConnectAppID string `json:"wechat_connect_app_id"`
|
||||||
WeChatConnectAppSecretConfigured bool `json:"wechat_connect_app_secret_configured"`
|
WeChatConnectAppSecretConfigured bool `json:"wechat_connect_app_secret_configured"`
|
||||||
|
WeChatConnectOpenEnabled bool `json:"wechat_connect_open_enabled"`
|
||||||
|
WeChatConnectMPEnabled bool `json:"wechat_connect_mp_enabled"`
|
||||||
WeChatConnectMode string `json:"wechat_connect_mode"`
|
WeChatConnectMode string `json:"wechat_connect_mode"`
|
||||||
WeChatConnectScopes string `json:"wechat_connect_scopes"`
|
WeChatConnectScopes string `json:"wechat_connect_scopes"`
|
||||||
WeChatConnectRedirectURL string `json:"wechat_connect_redirect_url"`
|
WeChatConnectRedirectURL string `json:"wechat_connect_redirect_url"`
|
||||||
|
|||||||
@@ -91,6 +91,8 @@ func TestSettingHandler_GetPublicSettings_ExposesWeChatOAuthModeCapabilities(t *
|
|||||||
service.SettingKeyWeChatConnectAppSecret: "wx-mp-secret",
|
service.SettingKeyWeChatConnectAppSecret: "wx-mp-secret",
|
||||||
service.SettingKeyWeChatConnectMode: "mp",
|
service.SettingKeyWeChatConnectMode: "mp",
|
||||||
service.SettingKeyWeChatConnectScopes: "snsapi_base",
|
service.SettingKeyWeChatConnectScopes: "snsapi_base",
|
||||||
|
service.SettingKeyWeChatConnectOpenEnabled: "true",
|
||||||
|
service.SettingKeyWeChatConnectMPEnabled: "true",
|
||||||
service.SettingKeyWeChatConnectRedirectURL: "https://api.example.com/api/v1/auth/oauth/wechat/callback",
|
service.SettingKeyWeChatConnectRedirectURL: "https://api.example.com/api/v1/auth/oauth/wechat/callback",
|
||||||
service.SettingKeyWeChatConnectFrontendRedirectURL: "/auth/wechat/callback",
|
service.SettingKeyWeChatConnectFrontendRedirectURL: "/auth/wechat/callback",
|
||||||
},
|
},
|
||||||
@@ -115,6 +117,6 @@ func TestSettingHandler_GetPublicSettings_ExposesWeChatOAuthModeCapabilities(t *
|
|||||||
require.NoError(t, json.Unmarshal(recorder.Body.Bytes(), &resp))
|
require.NoError(t, json.Unmarshal(recorder.Body.Bytes(), &resp))
|
||||||
require.Equal(t, 0, resp.Code)
|
require.Equal(t, 0, resp.Code)
|
||||||
require.True(t, resp.Data.WeChatOAuthEnabled)
|
require.True(t, resp.Data.WeChatOAuthEnabled)
|
||||||
require.False(t, resp.Data.WeChatOAuthOpenEnabled)
|
require.True(t, resp.Data.WeChatOAuthOpenEnabled)
|
||||||
require.True(t, resp.Data.WeChatOAuthMPEnabled)
|
require.True(t, resp.Data.WeChatOAuthMPEnabled)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -115,6 +115,8 @@ const (
|
|||||||
SettingKeyWeChatConnectEnabled = "wechat_connect_enabled"
|
SettingKeyWeChatConnectEnabled = "wechat_connect_enabled"
|
||||||
SettingKeyWeChatConnectAppID = "wechat_connect_app_id"
|
SettingKeyWeChatConnectAppID = "wechat_connect_app_id"
|
||||||
SettingKeyWeChatConnectAppSecret = "wechat_connect_app_secret"
|
SettingKeyWeChatConnectAppSecret = "wechat_connect_app_secret"
|
||||||
|
SettingKeyWeChatConnectOpenEnabled = "wechat_connect_open_enabled"
|
||||||
|
SettingKeyWeChatConnectMPEnabled = "wechat_connect_mp_enabled"
|
||||||
SettingKeyWeChatConnectMode = "wechat_connect_mode"
|
SettingKeyWeChatConnectMode = "wechat_connect_mode"
|
||||||
SettingKeyWeChatConnectScopes = "wechat_connect_scopes"
|
SettingKeyWeChatConnectScopes = "wechat_connect_scopes"
|
||||||
SettingKeyWeChatConnectRedirectURL = "wechat_connect_redirect_url"
|
SettingKeyWeChatConnectRedirectURL = "wechat_connect_redirect_url"
|
||||||
|
|||||||
@@ -519,7 +519,7 @@ func (s *PaymentService) getWeChatPaymentOAuthCredential(ctx context.Context) (s
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
cfg, err := (&SettingService{settingRepo: s.configService.settingRepo}).GetWeChatConnectOAuthConfig(ctx)
|
cfg, err := (&SettingService{settingRepo: s.configService.settingRepo}).GetWeChatConnectOAuthConfig(ctx)
|
||||||
if err != nil || cfg.Mode != "mp" || strings.TrimSpace(cfg.AppID) == "" || strings.TrimSpace(cfg.AppSecret) == "" {
|
if err != nil || !cfg.SupportsMode("mp") || strings.TrimSpace(cfg.AppID) == "" || strings.TrimSpace(cfg.AppSecret) == "" {
|
||||||
return "", "", infraerrors.ServiceUnavailable(
|
return "", "", infraerrors.ServiceUnavailable(
|
||||||
"WECHAT_PAYMENT_MP_NOT_CONFIGURED",
|
"WECHAT_PAYMENT_MP_NOT_CONFIGURED",
|
||||||
"wechat in-app payment requires a complete WeChat MP OAuth credential",
|
"wechat in-app payment requires a complete WeChat MP OAuth credential",
|
||||||
|
|||||||
@@ -209,6 +209,39 @@ func normalizeWeChatConnectScopeSetting(raw, mode string) string {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func parseWeChatConnectCapabilitySettings(settings map[string]string, enabled bool, mode string) (bool, bool) {
|
||||||
|
mode = normalizeWeChatConnectModeSetting(mode)
|
||||||
|
rawOpen, hasOpen := settings[SettingKeyWeChatConnectOpenEnabled]
|
||||||
|
rawMP, hasMP := settings[SettingKeyWeChatConnectMPEnabled]
|
||||||
|
openConfigured := hasOpen && strings.TrimSpace(rawOpen) != ""
|
||||||
|
mpConfigured := hasMP && strings.TrimSpace(rawMP) != ""
|
||||||
|
|
||||||
|
if openConfigured || mpConfigured {
|
||||||
|
openEnabled := strings.TrimSpace(rawOpen) == "true"
|
||||||
|
mpEnabled := strings.TrimSpace(rawMP) == "true"
|
||||||
|
return openEnabled, mpEnabled
|
||||||
|
}
|
||||||
|
|
||||||
|
if !enabled {
|
||||||
|
return false, false
|
||||||
|
}
|
||||||
|
if mode == "mp" {
|
||||||
|
return false, true
|
||||||
|
}
|
||||||
|
return true, false
|
||||||
|
}
|
||||||
|
|
||||||
|
func normalizeWeChatConnectStoredMode(openEnabled, mpEnabled bool, mode string) string {
|
||||||
|
switch {
|
||||||
|
case mpEnabled:
|
||||||
|
return "mp"
|
||||||
|
case openEnabled:
|
||||||
|
return "open"
|
||||||
|
default:
|
||||||
|
return normalizeWeChatConnectModeSetting(mode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// NewSettingService 创建系统设置服务实例
|
// NewSettingService 创建系统设置服务实例
|
||||||
func NewSettingService(settingRepo SettingRepository, cfg *config.Config) *SettingService {
|
func NewSettingService(settingRepo SettingRepository, cfg *config.Config) *SettingService {
|
||||||
return &SettingService{
|
return &SettingService{
|
||||||
@@ -277,6 +310,8 @@ func (s *SettingService) GetPublicSettings(ctx context.Context) (*PublicSettings
|
|||||||
SettingKeyWeChatConnectEnabled,
|
SettingKeyWeChatConnectEnabled,
|
||||||
SettingKeyWeChatConnectAppID,
|
SettingKeyWeChatConnectAppID,
|
||||||
SettingKeyWeChatConnectAppSecret,
|
SettingKeyWeChatConnectAppSecret,
|
||||||
|
SettingKeyWeChatConnectOpenEnabled,
|
||||||
|
SettingKeyWeChatConnectMPEnabled,
|
||||||
SettingKeyWeChatConnectMode,
|
SettingKeyWeChatConnectMode,
|
||||||
SettingKeyWeChatConnectScopes,
|
SettingKeyWeChatConnectScopes,
|
||||||
SettingKeyWeChatConnectRedirectURL,
|
SettingKeyWeChatConnectRedirectURL,
|
||||||
@@ -475,12 +510,19 @@ func DefaultWeChatConnectScopesForMode(mode string) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *SettingService) parseWeChatConnectOAuthConfig(settings map[string]string) (WeChatConnectOAuthConfig, error) {
|
func (s *SettingService) parseWeChatConnectOAuthConfig(settings map[string]string) (WeChatConnectOAuthConfig, error) {
|
||||||
|
enabled := settings[SettingKeyWeChatConnectEnabled] == "true"
|
||||||
|
mode := normalizeWeChatConnectModeSetting(settings[SettingKeyWeChatConnectMode])
|
||||||
|
openEnabled, mpEnabled := parseWeChatConnectCapabilitySettings(settings, enabled, mode)
|
||||||
|
mode = normalizeWeChatConnectStoredMode(openEnabled, mpEnabled, mode)
|
||||||
|
|
||||||
cfg := WeChatConnectOAuthConfig{
|
cfg := WeChatConnectOAuthConfig{
|
||||||
Enabled: settings[SettingKeyWeChatConnectEnabled] == "true",
|
Enabled: enabled,
|
||||||
AppID: strings.TrimSpace(settings[SettingKeyWeChatConnectAppID]),
|
AppID: strings.TrimSpace(settings[SettingKeyWeChatConnectAppID]),
|
||||||
AppSecret: strings.TrimSpace(settings[SettingKeyWeChatConnectAppSecret]),
|
AppSecret: strings.TrimSpace(settings[SettingKeyWeChatConnectAppSecret]),
|
||||||
Mode: normalizeWeChatConnectModeSetting(settings[SettingKeyWeChatConnectMode]),
|
OpenEnabled: openEnabled,
|
||||||
Scopes: normalizeWeChatConnectScopeSetting(settings[SettingKeyWeChatConnectScopes], settings[SettingKeyWeChatConnectMode]),
|
MPEnabled: mpEnabled,
|
||||||
|
Mode: mode,
|
||||||
|
Scopes: normalizeWeChatConnectScopeSetting(settings[SettingKeyWeChatConnectScopes], mode),
|
||||||
RedirectURL: strings.TrimSpace(settings[SettingKeyWeChatConnectRedirectURL]),
|
RedirectURL: strings.TrimSpace(settings[SettingKeyWeChatConnectRedirectURL]),
|
||||||
FrontendRedirectURL: strings.TrimSpace(settings[SettingKeyWeChatConnectFrontendRedirectURL]),
|
FrontendRedirectURL: strings.TrimSpace(settings[SettingKeyWeChatConnectFrontendRedirectURL]),
|
||||||
}
|
}
|
||||||
@@ -488,7 +530,7 @@ func (s *SettingService) parseWeChatConnectOAuthConfig(settings map[string]strin
|
|||||||
cfg.FrontendRedirectURL = defaultWeChatConnectFrontend
|
cfg.FrontendRedirectURL = defaultWeChatConnectFrontend
|
||||||
}
|
}
|
||||||
|
|
||||||
if !cfg.Enabled {
|
if !cfg.Enabled || (!cfg.OpenEnabled && !cfg.MPEnabled) {
|
||||||
return WeChatConnectOAuthConfig{}, infraerrors.NotFound("OAUTH_DISABLED", "wechat oauth is disabled")
|
return WeChatConnectOAuthConfig{}, infraerrors.NotFound("OAUTH_DISABLED", "wechat oauth is disabled")
|
||||||
}
|
}
|
||||||
if cfg.AppID == "" {
|
if cfg.AppID == "" {
|
||||||
@@ -517,7 +559,7 @@ func (s *SettingService) weChatOAuthCapabilitiesFromSettings(settings map[string
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return false, false, false
|
return false, false, false
|
||||||
}
|
}
|
||||||
return true, cfg.Mode == "open", cfg.Mode == "mp"
|
return true, cfg.OpenEnabled, cfg.MPEnabled
|
||||||
}
|
}
|
||||||
|
|
||||||
// filterUserVisibleMenuItems filters out admin-only menu items from a raw JSON
|
// filterUserVisibleMenuItems filters out admin-only menu items from a raw JSON
|
||||||
@@ -702,7 +744,11 @@ func (s *SettingService) buildSystemSettingsUpdates(ctx context.Context, setting
|
|||||||
settings.PaymentVisibleMethodWxpaySource = wxpaySource
|
settings.PaymentVisibleMethodWxpaySource = wxpaySource
|
||||||
settings.WeChatConnectAppID = strings.TrimSpace(settings.WeChatConnectAppID)
|
settings.WeChatConnectAppID = strings.TrimSpace(settings.WeChatConnectAppID)
|
||||||
settings.WeChatConnectAppSecret = strings.TrimSpace(settings.WeChatConnectAppSecret)
|
settings.WeChatConnectAppSecret = strings.TrimSpace(settings.WeChatConnectAppSecret)
|
||||||
settings.WeChatConnectMode = normalizeWeChatConnectModeSetting(settings.WeChatConnectMode)
|
settings.WeChatConnectMode = normalizeWeChatConnectStoredMode(
|
||||||
|
settings.WeChatConnectOpenEnabled,
|
||||||
|
settings.WeChatConnectMPEnabled,
|
||||||
|
settings.WeChatConnectMode,
|
||||||
|
)
|
||||||
settings.WeChatConnectScopes = normalizeWeChatConnectScopeSetting(settings.WeChatConnectScopes, settings.WeChatConnectMode)
|
settings.WeChatConnectScopes = normalizeWeChatConnectScopeSetting(settings.WeChatConnectScopes, settings.WeChatConnectMode)
|
||||||
settings.WeChatConnectRedirectURL = strings.TrimSpace(settings.WeChatConnectRedirectURL)
|
settings.WeChatConnectRedirectURL = strings.TrimSpace(settings.WeChatConnectRedirectURL)
|
||||||
settings.WeChatConnectFrontendRedirectURL = strings.TrimSpace(settings.WeChatConnectFrontendRedirectURL)
|
settings.WeChatConnectFrontendRedirectURL = strings.TrimSpace(settings.WeChatConnectFrontendRedirectURL)
|
||||||
@@ -781,6 +827,8 @@ func (s *SettingService) buildSystemSettingsUpdates(ctx context.Context, setting
|
|||||||
// WeChat Connect OAuth 登录
|
// WeChat Connect OAuth 登录
|
||||||
updates[SettingKeyWeChatConnectEnabled] = strconv.FormatBool(settings.WeChatConnectEnabled)
|
updates[SettingKeyWeChatConnectEnabled] = strconv.FormatBool(settings.WeChatConnectEnabled)
|
||||||
updates[SettingKeyWeChatConnectAppID] = settings.WeChatConnectAppID
|
updates[SettingKeyWeChatConnectAppID] = settings.WeChatConnectAppID
|
||||||
|
updates[SettingKeyWeChatConnectOpenEnabled] = strconv.FormatBool(settings.WeChatConnectOpenEnabled)
|
||||||
|
updates[SettingKeyWeChatConnectMPEnabled] = strconv.FormatBool(settings.WeChatConnectMPEnabled)
|
||||||
updates[SettingKeyWeChatConnectMode] = settings.WeChatConnectMode
|
updates[SettingKeyWeChatConnectMode] = settings.WeChatConnectMode
|
||||||
updates[SettingKeyWeChatConnectScopes] = settings.WeChatConnectScopes
|
updates[SettingKeyWeChatConnectScopes] = settings.WeChatConnectScopes
|
||||||
updates[SettingKeyWeChatConnectRedirectURL] = settings.WeChatConnectRedirectURL
|
updates[SettingKeyWeChatConnectRedirectURL] = settings.WeChatConnectRedirectURL
|
||||||
@@ -1296,6 +1344,8 @@ func (s *SettingService) InitializeDefaultSettings(ctx context.Context) error {
|
|||||||
SettingKeyCustomMenuItems: "[]",
|
SettingKeyCustomMenuItems: "[]",
|
||||||
SettingKeyCustomEndpoints: "[]",
|
SettingKeyCustomEndpoints: "[]",
|
||||||
SettingKeyWeChatConnectEnabled: "false",
|
SettingKeyWeChatConnectEnabled: "false",
|
||||||
|
SettingKeyWeChatConnectOpenEnabled: "false",
|
||||||
|
SettingKeyWeChatConnectMPEnabled: "false",
|
||||||
SettingKeyWeChatConnectMode: "open",
|
SettingKeyWeChatConnectMode: "open",
|
||||||
SettingKeyWeChatConnectScopes: "snsapi_login",
|
SettingKeyWeChatConnectScopes: "snsapi_login",
|
||||||
SettingKeyWeChatConnectFrontendRedirectURL: defaultWeChatConnectFrontend,
|
SettingKeyWeChatConnectFrontendRedirectURL: defaultWeChatConnectFrontend,
|
||||||
@@ -1307,22 +1357,22 @@ func (s *SettingService) InitializeDefaultSettings(ctx context.Context) error {
|
|||||||
SettingKeyAuthSourceDefaultEmailBalance: "0",
|
SettingKeyAuthSourceDefaultEmailBalance: "0",
|
||||||
SettingKeyAuthSourceDefaultEmailConcurrency: "5",
|
SettingKeyAuthSourceDefaultEmailConcurrency: "5",
|
||||||
SettingKeyAuthSourceDefaultEmailSubscriptions: "[]",
|
SettingKeyAuthSourceDefaultEmailSubscriptions: "[]",
|
||||||
SettingKeyAuthSourceDefaultEmailGrantOnSignup: "true",
|
SettingKeyAuthSourceDefaultEmailGrantOnSignup: "false",
|
||||||
SettingKeyAuthSourceDefaultEmailGrantOnFirstBind: "false",
|
SettingKeyAuthSourceDefaultEmailGrantOnFirstBind: "false",
|
||||||
SettingKeyAuthSourceDefaultLinuxDoBalance: "0",
|
SettingKeyAuthSourceDefaultLinuxDoBalance: "0",
|
||||||
SettingKeyAuthSourceDefaultLinuxDoConcurrency: "5",
|
SettingKeyAuthSourceDefaultLinuxDoConcurrency: "5",
|
||||||
SettingKeyAuthSourceDefaultLinuxDoSubscriptions: "[]",
|
SettingKeyAuthSourceDefaultLinuxDoSubscriptions: "[]",
|
||||||
SettingKeyAuthSourceDefaultLinuxDoGrantOnSignup: "true",
|
SettingKeyAuthSourceDefaultLinuxDoGrantOnSignup: "false",
|
||||||
SettingKeyAuthSourceDefaultLinuxDoGrantOnFirstBind: "false",
|
SettingKeyAuthSourceDefaultLinuxDoGrantOnFirstBind: "false",
|
||||||
SettingKeyAuthSourceDefaultOIDCBalance: "0",
|
SettingKeyAuthSourceDefaultOIDCBalance: "0",
|
||||||
SettingKeyAuthSourceDefaultOIDCConcurrency: "5",
|
SettingKeyAuthSourceDefaultOIDCConcurrency: "5",
|
||||||
SettingKeyAuthSourceDefaultOIDCSubscriptions: "[]",
|
SettingKeyAuthSourceDefaultOIDCSubscriptions: "[]",
|
||||||
SettingKeyAuthSourceDefaultOIDCGrantOnSignup: "true",
|
SettingKeyAuthSourceDefaultOIDCGrantOnSignup: "false",
|
||||||
SettingKeyAuthSourceDefaultOIDCGrantOnFirstBind: "false",
|
SettingKeyAuthSourceDefaultOIDCGrantOnFirstBind: "false",
|
||||||
SettingKeyAuthSourceDefaultWeChatBalance: "0",
|
SettingKeyAuthSourceDefaultWeChatBalance: "0",
|
||||||
SettingKeyAuthSourceDefaultWeChatConcurrency: "5",
|
SettingKeyAuthSourceDefaultWeChatConcurrency: "5",
|
||||||
SettingKeyAuthSourceDefaultWeChatSubscriptions: "[]",
|
SettingKeyAuthSourceDefaultWeChatSubscriptions: "[]",
|
||||||
SettingKeyAuthSourceDefaultWeChatGrantOnSignup: "true",
|
SettingKeyAuthSourceDefaultWeChatGrantOnSignup: "false",
|
||||||
SettingKeyAuthSourceDefaultWeChatGrantOnFirstBind: "false",
|
SettingKeyAuthSourceDefaultWeChatGrantOnFirstBind: "false",
|
||||||
SettingKeyForceEmailOnThirdPartySignup: "false",
|
SettingKeyForceEmailOnThirdPartySignup: "false",
|
||||||
SettingKeySMTPPort: "587",
|
SettingKeySMTPPort: "587",
|
||||||
@@ -1595,8 +1645,17 @@ func (s *SettingService) parseSettings(settings map[string]string) *SystemSettin
|
|||||||
result.WeChatConnectAppID = strings.TrimSpace(settings[SettingKeyWeChatConnectAppID])
|
result.WeChatConnectAppID = strings.TrimSpace(settings[SettingKeyWeChatConnectAppID])
|
||||||
result.WeChatConnectAppSecret = strings.TrimSpace(settings[SettingKeyWeChatConnectAppSecret])
|
result.WeChatConnectAppSecret = strings.TrimSpace(settings[SettingKeyWeChatConnectAppSecret])
|
||||||
result.WeChatConnectAppSecretConfigured = result.WeChatConnectAppSecret != ""
|
result.WeChatConnectAppSecretConfigured = result.WeChatConnectAppSecret != ""
|
||||||
result.WeChatConnectMode = normalizeWeChatConnectModeSetting(settings[SettingKeyWeChatConnectMode])
|
result.WeChatConnectOpenEnabled, result.WeChatConnectMPEnabled = parseWeChatConnectCapabilitySettings(
|
||||||
result.WeChatConnectScopes = normalizeWeChatConnectScopeSetting(settings[SettingKeyWeChatConnectScopes], settings[SettingKeyWeChatConnectMode])
|
settings,
|
||||||
|
result.WeChatConnectEnabled,
|
||||||
|
settings[SettingKeyWeChatConnectMode],
|
||||||
|
)
|
||||||
|
result.WeChatConnectMode = normalizeWeChatConnectStoredMode(
|
||||||
|
result.WeChatConnectOpenEnabled,
|
||||||
|
result.WeChatConnectMPEnabled,
|
||||||
|
settings[SettingKeyWeChatConnectMode],
|
||||||
|
)
|
||||||
|
result.WeChatConnectScopes = normalizeWeChatConnectScopeSetting(settings[SettingKeyWeChatConnectScopes], result.WeChatConnectMode)
|
||||||
result.WeChatConnectRedirectURL = strings.TrimSpace(settings[SettingKeyWeChatConnectRedirectURL])
|
result.WeChatConnectRedirectURL = strings.TrimSpace(settings[SettingKeyWeChatConnectRedirectURL])
|
||||||
result.WeChatConnectFrontendRedirectURL = strings.TrimSpace(settings[SettingKeyWeChatConnectFrontendRedirectURL])
|
result.WeChatConnectFrontendRedirectURL = strings.TrimSpace(settings[SettingKeyWeChatConnectFrontendRedirectURL])
|
||||||
if result.WeChatConnectFrontendRedirectURL == "" {
|
if result.WeChatConnectFrontendRedirectURL == "" {
|
||||||
@@ -1744,7 +1803,7 @@ func parseProviderDefaultGrantSettings(settings map[string]string, keys authSour
|
|||||||
Balance: defaultAuthSourceBalance,
|
Balance: defaultAuthSourceBalance,
|
||||||
Concurrency: defaultAuthSourceConcurrency,
|
Concurrency: defaultAuthSourceConcurrency,
|
||||||
Subscriptions: []DefaultSubscriptionSetting{},
|
Subscriptions: []DefaultSubscriptionSetting{},
|
||||||
GrantOnSignup: true,
|
GrantOnSignup: false,
|
||||||
GrantOnFirstBind: false,
|
GrantOnFirstBind: false,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2092,6 +2151,8 @@ func (s *SettingService) GetWeChatConnectOAuthConfig(ctx context.Context) (WeCha
|
|||||||
SettingKeyWeChatConnectEnabled,
|
SettingKeyWeChatConnectEnabled,
|
||||||
SettingKeyWeChatConnectAppID,
|
SettingKeyWeChatConnectAppID,
|
||||||
SettingKeyWeChatConnectAppSecret,
|
SettingKeyWeChatConnectAppSecret,
|
||||||
|
SettingKeyWeChatConnectOpenEnabled,
|
||||||
|
SettingKeyWeChatConnectMPEnabled,
|
||||||
SettingKeyWeChatConnectMode,
|
SettingKeyWeChatConnectMode,
|
||||||
SettingKeyWeChatConnectScopes,
|
SettingKeyWeChatConnectScopes,
|
||||||
SettingKeyWeChatConnectRedirectURL,
|
SettingKeyWeChatConnectRedirectURL,
|
||||||
|
|||||||
@@ -81,10 +81,12 @@ func TestSettingService_GetAuthSourceDefaultSettings_ParsesValuesAndDefaults(t *
|
|||||||
require.Equal(t, 0.0, got.LinuxDo.Balance)
|
require.Equal(t, 0.0, got.LinuxDo.Balance)
|
||||||
require.Equal(t, 5, got.LinuxDo.Concurrency)
|
require.Equal(t, 5, got.LinuxDo.Concurrency)
|
||||||
require.Equal(t, []DefaultSubscriptionSetting{}, got.LinuxDo.Subscriptions)
|
require.Equal(t, []DefaultSubscriptionSetting{}, got.LinuxDo.Subscriptions)
|
||||||
require.True(t, got.LinuxDo.GrantOnSignup)
|
require.False(t, got.LinuxDo.GrantOnSignup)
|
||||||
require.True(t, got.LinuxDo.GrantOnFirstBind)
|
require.True(t, got.LinuxDo.GrantOnFirstBind)
|
||||||
require.Equal(t, 5, got.OIDC.Concurrency)
|
require.Equal(t, 5, got.OIDC.Concurrency)
|
||||||
require.Equal(t, 5, got.WeChat.Concurrency)
|
require.Equal(t, 5, got.WeChat.Concurrency)
|
||||||
|
require.False(t, got.OIDC.GrantOnSignup)
|
||||||
|
require.False(t, got.WeChat.GrantOnSignup)
|
||||||
require.True(t, got.ForceEmailOnThirdPartySignup)
|
require.True(t, got.ForceEmailOnThirdPartySignup)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -99,6 +99,8 @@ func TestSettingService_GetPublicSettings_ExposesWeChatOAuthModeCapabilities(t *
|
|||||||
SettingKeyWeChatConnectAppSecret: "wx-mp-secret",
|
SettingKeyWeChatConnectAppSecret: "wx-mp-secret",
|
||||||
SettingKeyWeChatConnectMode: "mp",
|
SettingKeyWeChatConnectMode: "mp",
|
||||||
SettingKeyWeChatConnectScopes: "snsapi_base",
|
SettingKeyWeChatConnectScopes: "snsapi_base",
|
||||||
|
SettingKeyWeChatConnectOpenEnabled: "true",
|
||||||
|
SettingKeyWeChatConnectMPEnabled: "true",
|
||||||
SettingKeyWeChatConnectRedirectURL: "https://api.example.com/api/v1/auth/oauth/wechat/callback",
|
SettingKeyWeChatConnectRedirectURL: "https://api.example.com/api/v1/auth/oauth/wechat/callback",
|
||||||
SettingKeyWeChatConnectFrontendRedirectURL: "/auth/wechat/callback",
|
SettingKeyWeChatConnectFrontendRedirectURL: "/auth/wechat/callback",
|
||||||
},
|
},
|
||||||
@@ -107,6 +109,6 @@ func TestSettingService_GetPublicSettings_ExposesWeChatOAuthModeCapabilities(t *
|
|||||||
settings, err := svc.GetPublicSettings(context.Background())
|
settings, err := svc.GetPublicSettings(context.Background())
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.True(t, settings.WeChatOAuthEnabled)
|
require.True(t, settings.WeChatOAuthEnabled)
|
||||||
require.False(t, settings.WeChatOAuthOpenEnabled)
|
require.True(t, settings.WeChatOAuthOpenEnabled)
|
||||||
require.True(t, settings.WeChatOAuthMPEnabled)
|
require.True(t, settings.WeChatOAuthMPEnabled)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -59,6 +59,8 @@ func TestSettingService_GetWeChatConnectOAuthConfig_UsesDatabaseOverrides(t *tes
|
|||||||
SettingKeyWeChatConnectAppSecret: "wx-db-secret",
|
SettingKeyWeChatConnectAppSecret: "wx-db-secret",
|
||||||
SettingKeyWeChatConnectMode: "mp",
|
SettingKeyWeChatConnectMode: "mp",
|
||||||
SettingKeyWeChatConnectScopes: "snsapi_base",
|
SettingKeyWeChatConnectScopes: "snsapi_base",
|
||||||
|
SettingKeyWeChatConnectOpenEnabled: "true",
|
||||||
|
SettingKeyWeChatConnectMPEnabled: "true",
|
||||||
SettingKeyWeChatConnectRedirectURL: "https://api.example.com/api/v1/auth/oauth/wechat/callback",
|
SettingKeyWeChatConnectRedirectURL: "https://api.example.com/api/v1/auth/oauth/wechat/callback",
|
||||||
SettingKeyWeChatConnectFrontendRedirectURL: "/auth/wechat/callback",
|
SettingKeyWeChatConnectFrontendRedirectURL: "/auth/wechat/callback",
|
||||||
},
|
},
|
||||||
@@ -70,6 +72,8 @@ func TestSettingService_GetWeChatConnectOAuthConfig_UsesDatabaseOverrides(t *tes
|
|||||||
require.True(t, got.Enabled)
|
require.True(t, got.Enabled)
|
||||||
require.Equal(t, "wx-db-app", got.AppID)
|
require.Equal(t, "wx-db-app", got.AppID)
|
||||||
require.Equal(t, "wx-db-secret", got.AppSecret)
|
require.Equal(t, "wx-db-secret", got.AppSecret)
|
||||||
|
require.True(t, got.OpenEnabled)
|
||||||
|
require.True(t, got.MPEnabled)
|
||||||
require.Equal(t, "mp", got.Mode)
|
require.Equal(t, "mp", got.Mode)
|
||||||
require.Equal(t, "snsapi_base", got.Scopes)
|
require.Equal(t, "snsapi_base", got.Scopes)
|
||||||
require.Equal(t, "https://api.example.com/api/v1/auth/oauth/wechat/callback", got.RedirectURL)
|
require.Equal(t, "https://api.example.com/api/v1/auth/oauth/wechat/callback", got.RedirectURL)
|
||||||
|
|||||||
@@ -36,6 +36,8 @@ type SystemSettings struct {
|
|||||||
WeChatConnectAppID string
|
WeChatConnectAppID string
|
||||||
WeChatConnectAppSecret string
|
WeChatConnectAppSecret string
|
||||||
WeChatConnectAppSecretConfigured bool
|
WeChatConnectAppSecretConfigured bool
|
||||||
|
WeChatConnectOpenEnabled bool
|
||||||
|
WeChatConnectMPEnabled bool
|
||||||
WeChatConnectMode string
|
WeChatConnectMode string
|
||||||
WeChatConnectScopes string
|
WeChatConnectScopes string
|
||||||
WeChatConnectRedirectURL string
|
WeChatConnectRedirectURL string
|
||||||
@@ -191,12 +193,30 @@ type WeChatConnectOAuthConfig struct {
|
|||||||
Enabled bool
|
Enabled bool
|
||||||
AppID string
|
AppID string
|
||||||
AppSecret string
|
AppSecret string
|
||||||
|
OpenEnabled bool
|
||||||
|
MPEnabled bool
|
||||||
Mode string
|
Mode string
|
||||||
Scopes string
|
Scopes string
|
||||||
RedirectURL string
|
RedirectURL string
|
||||||
FrontendRedirectURL string
|
FrontendRedirectURL string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (cfg WeChatConnectOAuthConfig) SupportsMode(mode string) bool {
|
||||||
|
switch normalizeWeChatConnectModeSetting(mode) {
|
||||||
|
case "mp":
|
||||||
|
return cfg.MPEnabled
|
||||||
|
default:
|
||||||
|
return cfg.OpenEnabled
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cfg WeChatConnectOAuthConfig) ScopeForMode(mode string) string {
|
||||||
|
if normalizeWeChatConnectModeSetting(mode) == "mp" {
|
||||||
|
return normalizeWeChatConnectScopeSetting(cfg.Scopes, "mp")
|
||||||
|
}
|
||||||
|
return defaultWeChatConnectScopeForMode("open")
|
||||||
|
}
|
||||||
|
|
||||||
// StreamTimeoutSettings 流超时处理配置(仅控制超时后的处理方式,超时判定由网关配置控制)
|
// StreamTimeoutSettings 流超时处理配置(仅控制超时后的处理方式,超时判定由网关配置控制)
|
||||||
type StreamTimeoutSettings struct {
|
type StreamTimeoutSettings struct {
|
||||||
// Enabled 是否启用流超时处理
|
// Enabled 是否启用流超时处理
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
INSERT INTO settings (key, value)
|
||||||
|
VALUES
|
||||||
|
(
|
||||||
|
'wechat_connect_open_enabled',
|
||||||
|
CASE
|
||||||
|
WHEN COALESCE((SELECT value FROM settings WHERE key = 'wechat_connect_enabled'), 'false') <> 'true' THEN 'false'
|
||||||
|
WHEN LOWER(TRIM(COALESCE((SELECT value FROM settings WHERE key = 'wechat_connect_mode'), 'open'))) = 'mp' THEN 'false'
|
||||||
|
ELSE 'true'
|
||||||
|
END
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'wechat_connect_mp_enabled',
|
||||||
|
CASE
|
||||||
|
WHEN COALESCE((SELECT value FROM settings WHERE key = 'wechat_connect_enabled'), 'false') <> 'true' THEN 'false'
|
||||||
|
WHEN LOWER(TRIM(COALESCE((SELECT value FROM settings WHERE key = 'wechat_connect_mode'), 'open'))) = 'mp' THEN 'true'
|
||||||
|
ELSE 'false'
|
||||||
|
END
|
||||||
|
),
|
||||||
|
('auth_source_default_email_grant_on_signup', 'false'),
|
||||||
|
('auth_source_default_linuxdo_grant_on_signup', 'false'),
|
||||||
|
('auth_source_default_oidc_grant_on_signup', 'false'),
|
||||||
|
('auth_source_default_wechat_grant_on_signup', 'false')
|
||||||
|
ON CONFLICT (key) DO NOTHING;
|
||||||
|
|
||||||
|
UPDATE settings
|
||||||
|
SET value = 'false'
|
||||||
|
WHERE key IN (
|
||||||
|
'auth_source_default_email_grant_on_signup',
|
||||||
|
'auth_source_default_linuxdo_grant_on_signup',
|
||||||
|
'auth_source_default_oidc_grant_on_signup',
|
||||||
|
'auth_source_default_wechat_grant_on_signup'
|
||||||
|
);
|
||||||
@@ -1,13 +1,13 @@
|
|||||||
import { describe, expect, it } from 'vitest'
|
import { describe, expect, it } from "vitest";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
appendAuthSourceDefaultsToUpdateRequest,
|
appendAuthSourceDefaultsToUpdateRequest,
|
||||||
buildAuthSourceDefaultsState,
|
buildAuthSourceDefaultsState,
|
||||||
type UpdateSettingsRequest,
|
type UpdateSettingsRequest,
|
||||||
} from '@/api/admin/settings'
|
} from "@/api/admin/settings";
|
||||||
|
|
||||||
describe('admin settings auth source defaults helpers', () => {
|
describe("admin settings auth source defaults helpers", () => {
|
||||||
it('builds auth source defaults state from flat settings fields', () => {
|
it("builds auth source defaults state from flat settings fields", () => {
|
||||||
const state = buildAuthSourceDefaultsState({
|
const state = buildAuthSourceDefaultsState({
|
||||||
auth_source_default_email_balance: 9.5,
|
auth_source_default_email_balance: 9.5,
|
||||||
auth_source_default_email_concurrency: 3,
|
auth_source_default_email_concurrency: 3,
|
||||||
@@ -23,7 +23,7 @@ describe('admin settings auth source defaults helpers', () => {
|
|||||||
],
|
],
|
||||||
auth_source_default_linuxdo_grant_on_signup: true,
|
auth_source_default_linuxdo_grant_on_signup: true,
|
||||||
auth_source_default_linuxdo_grant_on_first_bind: false,
|
auth_source_default_linuxdo_grant_on_first_bind: false,
|
||||||
})
|
});
|
||||||
|
|
||||||
expect(state.email).toEqual({
|
expect(state.email).toEqual({
|
||||||
balance: 9.5,
|
balance: 9.5,
|
||||||
@@ -31,34 +31,43 @@ describe('admin settings auth source defaults helpers', () => {
|
|||||||
subscriptions: [{ group_id: 1, validity_days: 30 }],
|
subscriptions: [{ group_id: 1, validity_days: 30 }],
|
||||||
grant_on_signup: false,
|
grant_on_signup: false,
|
||||||
grant_on_first_bind: true,
|
grant_on_first_bind: true,
|
||||||
})
|
});
|
||||||
expect(state.linuxdo).toEqual({
|
expect(state.linuxdo).toEqual({
|
||||||
balance: 6,
|
balance: 6,
|
||||||
concurrency: 8,
|
concurrency: 8,
|
||||||
subscriptions: [{ group_id: 2, validity_days: 60 }],
|
subscriptions: [{ group_id: 2, validity_days: 60 }],
|
||||||
grant_on_signup: true,
|
grant_on_signup: true,
|
||||||
grant_on_first_bind: false,
|
grant_on_first_bind: false,
|
||||||
})
|
});
|
||||||
expect(state.oidc).toEqual({
|
expect(state.oidc).toEqual({
|
||||||
balance: 0,
|
balance: 0,
|
||||||
concurrency: 5,
|
concurrency: 5,
|
||||||
subscriptions: [],
|
subscriptions: [],
|
||||||
grant_on_signup: true,
|
grant_on_signup: false,
|
||||||
grant_on_first_bind: false,
|
grant_on_first_bind: false,
|
||||||
})
|
});
|
||||||
expect(state.wechat).toEqual({
|
expect(state.wechat).toEqual({
|
||||||
balance: 0,
|
balance: 0,
|
||||||
concurrency: 5,
|
concurrency: 5,
|
||||||
subscriptions: [],
|
subscriptions: [],
|
||||||
grant_on_signup: true,
|
grant_on_signup: false,
|
||||||
grant_on_first_bind: false,
|
grant_on_first_bind: false,
|
||||||
})
|
});
|
||||||
})
|
});
|
||||||
|
|
||||||
it('appends auth source defaults back onto update payload', () => {
|
it("defaults grant-on-signup to disabled when settings are missing", () => {
|
||||||
|
const state = buildAuthSourceDefaultsState({});
|
||||||
|
|
||||||
|
expect(state.email.grant_on_signup).toBe(false);
|
||||||
|
expect(state.linuxdo.grant_on_signup).toBe(false);
|
||||||
|
expect(state.oidc.grant_on_signup).toBe(false);
|
||||||
|
expect(state.wechat.grant_on_signup).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("appends auth source defaults back onto update payload", () => {
|
||||||
const payload: UpdateSettingsRequest = {
|
const payload: UpdateSettingsRequest = {
|
||||||
site_name: 'Sub2API',
|
site_name: "Sub2API",
|
||||||
}
|
};
|
||||||
|
|
||||||
appendAuthSourceDefaultsToUpdateRequest(payload, {
|
appendAuthSourceDefaultsToUpdateRequest(payload, {
|
||||||
email: {
|
email: {
|
||||||
@@ -89,13 +98,15 @@ describe('admin settings auth source defaults helpers', () => {
|
|||||||
grant_on_signup: false,
|
grant_on_signup: false,
|
||||||
grant_on_first_bind: false,
|
grant_on_first_bind: false,
|
||||||
},
|
},
|
||||||
})
|
});
|
||||||
|
|
||||||
expect(payload).toMatchObject({
|
expect(payload).toMatchObject({
|
||||||
site_name: 'Sub2API',
|
site_name: "Sub2API",
|
||||||
auth_source_default_email_balance: 1.25,
|
auth_source_default_email_balance: 1.25,
|
||||||
auth_source_default_email_concurrency: 2,
|
auth_source_default_email_concurrency: 2,
|
||||||
auth_source_default_email_subscriptions: [{ group_id: 3, validity_days: 7 }],
|
auth_source_default_email_subscriptions: [
|
||||||
|
{ group_id: 3, validity_days: 7 },
|
||||||
|
],
|
||||||
auth_source_default_email_grant_on_signup: true,
|
auth_source_default_email_grant_on_signup: true,
|
||||||
auth_source_default_email_grant_on_first_bind: false,
|
auth_source_default_email_grant_on_first_bind: false,
|
||||||
auth_source_default_linuxdo_balance: 0,
|
auth_source_default_linuxdo_balance: 0,
|
||||||
@@ -105,7 +116,9 @@ describe('admin settings auth source defaults helpers', () => {
|
|||||||
auth_source_default_linuxdo_grant_on_first_bind: true,
|
auth_source_default_linuxdo_grant_on_first_bind: true,
|
||||||
auth_source_default_oidc_balance: 4,
|
auth_source_default_oidc_balance: 4,
|
||||||
auth_source_default_oidc_concurrency: 9,
|
auth_source_default_oidc_concurrency: 9,
|
||||||
auth_source_default_oidc_subscriptions: [{ group_id: 9, validity_days: 90 }],
|
auth_source_default_oidc_subscriptions: [
|
||||||
|
{ group_id: 9, validity_days: 90 },
|
||||||
|
],
|
||||||
auth_source_default_oidc_grant_on_signup: true,
|
auth_source_default_oidc_grant_on_signup: true,
|
||||||
auth_source_default_oidc_grant_on_first_bind: true,
|
auth_source_default_oidc_grant_on_first_bind: true,
|
||||||
auth_source_default_wechat_balance: 2,
|
auth_source_default_wechat_balance: 2,
|
||||||
@@ -113,6 +126,6 @@ describe('admin settings auth source defaults helpers', () => {
|
|||||||
auth_source_default_wechat_subscriptions: [],
|
auth_source_default_wechat_subscriptions: [],
|
||||||
auth_source_default_wechat_grant_on_signup: false,
|
auth_source_default_wechat_grant_on_signup: false,
|
||||||
auth_source_default_wechat_grant_on_first_bind: false,
|
auth_source_default_wechat_grant_on_first_bind: false,
|
||||||
})
|
});
|
||||||
})
|
});
|
||||||
})
|
});
|
||||||
|
|||||||
@@ -167,7 +167,7 @@ export function buildAuthSourceDefaultsState(
|
|||||||
: [],
|
: [],
|
||||||
),
|
),
|
||||||
grant_on_signup:
|
grant_on_signup:
|
||||||
raw[`auth_source_default_${source}_grant_on_signup`] !== false,
|
raw[`auth_source_default_${source}_grant_on_signup`] === true,
|
||||||
grant_on_first_bind:
|
grant_on_first_bind:
|
||||||
raw[`auth_source_default_${source}_grant_on_first_bind`] === true,
|
raw[`auth_source_default_${source}_grant_on_first_bind`] === true,
|
||||||
};
|
};
|
||||||
@@ -239,6 +239,33 @@ export function defaultWeChatConnectScopesForMode(mode: unknown): string {
|
|||||||
: "snsapi_login";
|
: "snsapi_login";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function resolveWeChatConnectModeCapabilities(
|
||||||
|
openEnabled: unknown,
|
||||||
|
mpEnabled: unknown,
|
||||||
|
legacyMode: unknown,
|
||||||
|
): { openEnabled: boolean; mpEnabled: boolean } {
|
||||||
|
if (typeof openEnabled === "boolean" || typeof mpEnabled === "boolean") {
|
||||||
|
return {
|
||||||
|
openEnabled: openEnabled === true,
|
||||||
|
mpEnabled: mpEnabled === true,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return normalizeWeChatConnectMode(legacyMode) === "mp"
|
||||||
|
? { openEnabled: false, mpEnabled: true }
|
||||||
|
: { openEnabled: true, mpEnabled: false };
|
||||||
|
}
|
||||||
|
|
||||||
|
export function deriveWeChatConnectStoredMode(
|
||||||
|
openEnabled: boolean,
|
||||||
|
mpEnabled: boolean,
|
||||||
|
legacyMode: unknown,
|
||||||
|
): WeChatConnectMode {
|
||||||
|
if (mpEnabled) return "mp";
|
||||||
|
if (openEnabled) return "open";
|
||||||
|
return normalizeWeChatConnectMode(legacyMode);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* System settings interface
|
* System settings interface
|
||||||
*/
|
*/
|
||||||
@@ -315,6 +342,8 @@ export interface SystemSettings {
|
|||||||
wechat_connect_enabled: boolean;
|
wechat_connect_enabled: boolean;
|
||||||
wechat_connect_app_id: string;
|
wechat_connect_app_id: string;
|
||||||
wechat_connect_app_secret_configured: boolean;
|
wechat_connect_app_secret_configured: boolean;
|
||||||
|
wechat_connect_open_enabled?: boolean;
|
||||||
|
wechat_connect_mp_enabled?: boolean;
|
||||||
wechat_connect_mode: string;
|
wechat_connect_mode: string;
|
||||||
wechat_connect_scopes: string;
|
wechat_connect_scopes: string;
|
||||||
wechat_connect_redirect_url: string;
|
wechat_connect_redirect_url: string;
|
||||||
@@ -472,6 +501,8 @@ export interface UpdateSettingsRequest {
|
|||||||
wechat_connect_enabled?: boolean;
|
wechat_connect_enabled?: boolean;
|
||||||
wechat_connect_app_id?: string;
|
wechat_connect_app_id?: string;
|
||||||
wechat_connect_app_secret?: string;
|
wechat_connect_app_secret?: string;
|
||||||
|
wechat_connect_open_enabled?: boolean;
|
||||||
|
wechat_connect_mp_enabled?: boolean;
|
||||||
wechat_connect_mode?: string;
|
wechat_connect_mode?: string;
|
||||||
wechat_connect_scopes?: string;
|
wechat_connect_scopes?: string;
|
||||||
wechat_connect_redirect_url?: string;
|
wechat_connect_redirect_url?: string;
|
||||||
|
|||||||
@@ -1408,7 +1408,7 @@
|
|||||||
v-if="form.wechat_connect_enabled"
|
v-if="form.wechat_connect_enabled"
|
||||||
class="space-y-6 border-t border-gray-100 pt-4 dark:border-dark-700"
|
class="space-y-6 border-t border-gray-100 pt-4 dark:border-dark-700"
|
||||||
>
|
>
|
||||||
<div class="grid grid-cols-1 gap-6 lg:grid-cols-3">
|
<div class="grid grid-cols-1 gap-6 lg:grid-cols-2">
|
||||||
<div>
|
<div>
|
||||||
<label
|
<label
|
||||||
class="mb-2 block text-sm font-medium text-gray-700 dark:text-gray-300"
|
class="mb-2 block text-sm font-medium text-gray-700 dark:text-gray-300"
|
||||||
@@ -1463,69 +1463,74 @@
|
|||||||
}}
|
}}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div>
|
<div class="grid grid-cols-1 gap-6 lg:grid-cols-2">
|
||||||
|
<div class="space-y-3">
|
||||||
<label
|
<label
|
||||||
class="mb-2 block text-sm font-medium text-gray-700 dark:text-gray-300"
|
class="mb-2 block text-sm font-medium text-gray-700 dark:text-gray-300"
|
||||||
>
|
>
|
||||||
{{ localText("模式", "Mode") }}
|
{{ localText("模式", "Mode") }}
|
||||||
</label>
|
</label>
|
||||||
<select
|
<div
|
||||||
data-testid="wechat-connect-mode"
|
class="flex items-center justify-between rounded border border-gray-200 px-4 py-3 dark:border-dark-700"
|
||||||
v-model="form.wechat_connect_mode"
|
|
||||||
class="input font-mono text-sm"
|
|
||||||
@change="syncWeChatConnectMode"
|
|
||||||
>
|
>
|
||||||
<option value="open">
|
|
||||||
{{ localText("开放平台", "Open Platform") }}
|
|
||||||
</option>
|
|
||||||
<option value="mp">
|
|
||||||
{{
|
|
||||||
localText(
|
|
||||||
"公众号 / 小程序",
|
|
||||||
"Official Account / Mini Program",
|
|
||||||
)
|
|
||||||
}}
|
|
||||||
</option>
|
|
||||||
</select>
|
|
||||||
<p class="mt-1.5 text-xs text-gray-500 dark:text-gray-400">
|
|
||||||
{{
|
|
||||||
localText(
|
|
||||||
"open 对应微信开放平台,mp 对应公众号/小程序授权。",
|
|
||||||
"open maps to WeChat Open Platform, mp maps to Official Account / Mini Program authorization.",
|
|
||||||
)
|
|
||||||
}}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="grid grid-cols-1 gap-6 lg:grid-cols-2">
|
|
||||||
<div>
|
<div>
|
||||||
<label
|
<div class="font-medium text-gray-900 dark:text-white">
|
||||||
class="mb-2 block text-sm font-medium text-gray-700 dark:text-gray-300"
|
|
||||||
>
|
|
||||||
{{ localText("Scopes", "Scopes") }}
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
data-testid="wechat-connect-scopes"
|
|
||||||
v-model="form.wechat_connect_scopes"
|
|
||||||
type="text"
|
|
||||||
class="input font-mono text-sm"
|
|
||||||
:placeholder="
|
|
||||||
form.wechat_connect_mode === 'mp'
|
|
||||||
? 'snsapi_userinfo'
|
|
||||||
: 'snsapi_login'
|
|
||||||
"
|
|
||||||
/>
|
|
||||||
<p class="mt-1.5 text-xs text-gray-500 dark:text-gray-400">
|
|
||||||
{{
|
{{
|
||||||
localText(
|
localText(
|
||||||
"留空时会按模式自动回填默认值。",
|
"非微信环境使用开放平台",
|
||||||
"Leave empty to use the default scope for the selected mode.",
|
"Use Open outside WeChat",
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
</div>
|
||||||
|
<p
|
||||||
|
class="mt-0.5 text-xs text-gray-500 dark:text-gray-400"
|
||||||
|
>
|
||||||
|
{{
|
||||||
|
localText(
|
||||||
|
"浏览器不在微信内时,自动走开放平台扫码授权。",
|
||||||
|
"Use Open Platform QR authorization outside the WeChat browser.",
|
||||||
)
|
)
|
||||||
}}
|
}}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
<Toggle
|
||||||
|
v-model="form.wechat_connect_open_enabled"
|
||||||
|
data-testid="wechat-connect-open-enabled"
|
||||||
|
@update:model-value="syncWeChatConnectMode"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="flex items-center justify-between rounded border border-gray-200 px-4 py-3 dark:border-dark-700"
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
<div class="font-medium text-gray-900 dark:text-white">
|
||||||
|
{{
|
||||||
|
localText(
|
||||||
|
"微信环境使用公众号",
|
||||||
|
"Use MP inside WeChat",
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
</div>
|
||||||
|
<p
|
||||||
|
class="mt-0.5 text-xs text-gray-500 dark:text-gray-400"
|
||||||
|
>
|
||||||
|
{{
|
||||||
|
localText(
|
||||||
|
"浏览器在微信内时,自动走公众号授权。",
|
||||||
|
"Use Official Account authorization inside the WeChat browser.",
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<Toggle
|
||||||
|
v-model="form.wechat_connect_mp_enabled"
|
||||||
|
data-testid="wechat-connect-mp-enabled"
|
||||||
|
@update:model-value="syncWeChatConnectMode"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<label
|
<label
|
||||||
@@ -2246,13 +2251,14 @@
|
|||||||
<Toggle v-model="form.force_email_on_third_party_signup" />
|
<Toggle v-model="form.force_email_on_third_party_signup" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="grid grid-cols-1 gap-4 xl:grid-cols-2">
|
<div class="space-y-4">
|
||||||
<div
|
<div
|
||||||
v-for="authSource in authSourceDefaultsMeta"
|
v-for="authSource in authSourceDefaultsMeta"
|
||||||
:key="authSource.source"
|
:key="authSource.source"
|
||||||
class="rounded-xl border border-gray-200 p-4 dark:border-dark-700"
|
class="rounded-xl border border-gray-200 p-4 dark:border-dark-700"
|
||||||
>
|
>
|
||||||
<div class="mb-4">
|
<div class="flex items-center justify-between gap-4">
|
||||||
|
<div>
|
||||||
<div class="font-medium text-gray-900 dark:text-white">
|
<div class="font-medium text-gray-900 dark:text-white">
|
||||||
{{ authSource.title }}
|
{{ authSource.title }}
|
||||||
</div>
|
</div>
|
||||||
@@ -2260,6 +2266,27 @@
|
|||||||
{{ authSource.description }}
|
{{ authSource.description }}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
<Toggle
|
||||||
|
v-model="
|
||||||
|
authSourceDefaults[authSource.source].grant_on_signup
|
||||||
|
"
|
||||||
|
:data-testid="`auth-source-${authSource.source}-enabled`"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
v-if="authSourceDefaults[authSource.source].grant_on_signup"
|
||||||
|
:data-testid="`auth-source-${authSource.source}-panel`"
|
||||||
|
class="mt-4 space-y-4 border-t border-gray-100 pt-4 dark:border-dark-700"
|
||||||
|
>
|
||||||
|
<p class="text-sm text-gray-500 dark:text-gray-400">
|
||||||
|
{{
|
||||||
|
localText(
|
||||||
|
"以下默认值会在该来源注册新用户时发放;首次绑定时授权仅作用于已有账号绑定该来源。",
|
||||||
|
"These defaults apply when a new user registers through this source. Grant on first bind only applies when an existing user binds this source.",
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
</p>
|
||||||
|
|
||||||
<div class="grid grid-cols-1 gap-4 md:grid-cols-2">
|
<div class="grid grid-cols-1 gap-4 md:grid-cols-2">
|
||||||
<div>
|
<div>
|
||||||
@@ -2297,34 +2324,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mt-4 grid grid-cols-1 gap-3 md:grid-cols-2">
|
|
||||||
<div
|
|
||||||
class="flex items-center justify-between rounded border border-gray-200 px-4 py-3 dark:border-dark-700"
|
|
||||||
>
|
|
||||||
<div>
|
|
||||||
<label
|
|
||||||
class="font-medium text-gray-900 dark:text-white"
|
|
||||||
>
|
|
||||||
{{ localText("注册即授权", "Grant on signup") }}
|
|
||||||
</label>
|
|
||||||
<p
|
|
||||||
class="mt-0.5 text-xs text-gray-500 dark:text-gray-400"
|
|
||||||
>
|
|
||||||
{{
|
|
||||||
localText(
|
|
||||||
"来源首次注册成功后立即发放默认权益。",
|
|
||||||
"Grant default entitlements immediately after signup.",
|
|
||||||
)
|
|
||||||
}}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<Toggle
|
|
||||||
v-model="
|
|
||||||
authSourceDefaults[authSource.source].grant_on_signup
|
|
||||||
"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div
|
<div
|
||||||
class="flex items-center justify-between rounded border border-gray-200 px-4 py-3 dark:border-dark-700"
|
class="flex items-center justify-between rounded border border-gray-200 px-4 py-3 dark:border-dark-700"
|
||||||
>
|
>
|
||||||
@@ -2341,8 +2340,8 @@
|
|||||||
>
|
>
|
||||||
{{
|
{{
|
||||||
localText(
|
localText(
|
||||||
"来源首次绑定到现有账号时发放默认权益。",
|
"已有账号首次绑定该来源时发放默认权益。",
|
||||||
"Grant default entitlements when the source is first bound to an existing user.",
|
"Grant default entitlements when an existing user first binds this source.",
|
||||||
)
|
)
|
||||||
}}
|
}}
|
||||||
</p>
|
</p>
|
||||||
@@ -2354,11 +2353,7 @@
|
|||||||
"
|
"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
<div
|
|
||||||
class="mt-4 border-t border-gray-100 pt-4 dark:border-dark-700"
|
|
||||||
>
|
|
||||||
<div class="mb-3 flex items-center justify-between">
|
<div class="mb-3 flex items-center justify-between">
|
||||||
<div>
|
<div>
|
||||||
<label
|
<label
|
||||||
@@ -4710,12 +4705,13 @@ import { useI18n } from "vue-i18n";
|
|||||||
import { adminAPI } from "@/api";
|
import { adminAPI } from "@/api";
|
||||||
import {
|
import {
|
||||||
appendAuthSourceDefaultsToUpdateRequest,
|
appendAuthSourceDefaultsToUpdateRequest,
|
||||||
defaultWeChatConnectScopesForMode,
|
|
||||||
buildAuthSourceDefaultsState,
|
buildAuthSourceDefaultsState,
|
||||||
|
defaultWeChatConnectScopesForMode,
|
||||||
|
deriveWeChatConnectStoredMode,
|
||||||
getPaymentVisibleMethodSourceOptions,
|
getPaymentVisibleMethodSourceOptions,
|
||||||
normalizePaymentVisibleMethodSource,
|
normalizePaymentVisibleMethodSource,
|
||||||
normalizeDefaultSubscriptionSettings,
|
normalizeDefaultSubscriptionSettings,
|
||||||
normalizeWeChatConnectMode,
|
resolveWeChatConnectModeCapabilities,
|
||||||
} from "@/api/admin/settings";
|
} from "@/api/admin/settings";
|
||||||
import type {
|
import type {
|
||||||
AuthSourceDefaultsState,
|
AuthSourceDefaultsState,
|
||||||
@@ -4859,11 +4855,16 @@ interface DefaultSubscriptionGroupOption {
|
|||||||
[key: string]: unknown;
|
[key: string]: unknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
type SettingsForm = SystemSettings & {
|
type SettingsForm = Omit<
|
||||||
|
SystemSettings,
|
||||||
|
"wechat_connect_open_enabled" | "wechat_connect_mp_enabled"
|
||||||
|
> & {
|
||||||
smtp_password: string;
|
smtp_password: string;
|
||||||
turnstile_secret_key: string;
|
turnstile_secret_key: string;
|
||||||
linuxdo_connect_client_secret: string;
|
linuxdo_connect_client_secret: string;
|
||||||
wechat_connect_app_secret: string;
|
wechat_connect_app_secret: string;
|
||||||
|
wechat_connect_open_enabled: boolean;
|
||||||
|
wechat_connect_mp_enabled: boolean;
|
||||||
oidc_connect_client_secret: string;
|
oidc_connect_client_secret: string;
|
||||||
force_email_on_third_party_signup: boolean;
|
force_email_on_third_party_signup: boolean;
|
||||||
payment_visible_method_alipay_source: string;
|
payment_visible_method_alipay_source: string;
|
||||||
@@ -4958,6 +4959,8 @@ const form = reactive<SettingsForm>({
|
|||||||
wechat_connect_app_id: "",
|
wechat_connect_app_id: "",
|
||||||
wechat_connect_app_secret: "",
|
wechat_connect_app_secret: "",
|
||||||
wechat_connect_app_secret_configured: false,
|
wechat_connect_app_secret_configured: false,
|
||||||
|
wechat_connect_open_enabled: false,
|
||||||
|
wechat_connect_mp_enabled: false,
|
||||||
wechat_connect_mode: "open",
|
wechat_connect_mode: "open",
|
||||||
wechat_connect_scopes: "snsapi_login",
|
wechat_connect_scopes: "snsapi_login",
|
||||||
wechat_connect_redirect_url: "",
|
wechat_connect_redirect_url: "",
|
||||||
@@ -5452,14 +5455,21 @@ const wechatRedirectUrlSuggestion = computed(() => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
function syncWeChatConnectMode() {
|
function syncWeChatConnectMode() {
|
||||||
form.wechat_connect_mode = normalizeWeChatConnectMode(
|
const capabilities = resolveWeChatConnectModeCapabilities(
|
||||||
|
form.wechat_connect_open_enabled,
|
||||||
|
form.wechat_connect_mp_enabled,
|
||||||
|
form.wechat_connect_mode,
|
||||||
|
);
|
||||||
|
form.wechat_connect_open_enabled = capabilities.openEnabled;
|
||||||
|
form.wechat_connect_mp_enabled = capabilities.mpEnabled;
|
||||||
|
form.wechat_connect_mode = deriveWeChatConnectStoredMode(
|
||||||
|
capabilities.openEnabled,
|
||||||
|
capabilities.mpEnabled,
|
||||||
form.wechat_connect_mode,
|
form.wechat_connect_mode,
|
||||||
);
|
);
|
||||||
if (!form.wechat_connect_scopes.trim()) {
|
|
||||||
form.wechat_connect_scopes = defaultWeChatConnectScopesForMode(
|
form.wechat_connect_scopes = defaultWeChatConnectScopesForMode(
|
||||||
form.wechat_connect_mode,
|
form.wechat_connect_mode,
|
||||||
);
|
);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function setAndCopyWeChatRedirectUrl() {
|
async function setAndCopyWeChatRedirectUrl() {
|
||||||
@@ -5608,16 +5618,21 @@ async function loadSettings() {
|
|||||||
form.turnstile_secret_key = "";
|
form.turnstile_secret_key = "";
|
||||||
form.linuxdo_connect_client_secret = "";
|
form.linuxdo_connect_client_secret = "";
|
||||||
form.wechat_connect_app_secret = "";
|
form.wechat_connect_app_secret = "";
|
||||||
form.wechat_connect_mode = normalizeWeChatConnectMode(
|
const wechatCapabilities = resolveWeChatConnectModeCapabilities(
|
||||||
|
settings.wechat_connect_open_enabled,
|
||||||
|
settings.wechat_connect_mp_enabled,
|
||||||
settings.wechat_connect_mode,
|
settings.wechat_connect_mode,
|
||||||
);
|
);
|
||||||
const wechatConnectScopes =
|
form.wechat_connect_open_enabled = wechatCapabilities.openEnabled;
|
||||||
typeof settings.wechat_connect_scopes === "string"
|
form.wechat_connect_mp_enabled = wechatCapabilities.mpEnabled;
|
||||||
? settings.wechat_connect_scopes.trim()
|
form.wechat_connect_mode = deriveWeChatConnectStoredMode(
|
||||||
: "";
|
wechatCapabilities.openEnabled,
|
||||||
form.wechat_connect_scopes =
|
wechatCapabilities.mpEnabled,
|
||||||
wechatConnectScopes ||
|
settings.wechat_connect_mode,
|
||||||
defaultWeChatConnectScopesForMode(form.wechat_connect_mode);
|
);
|
||||||
|
form.wechat_connect_scopes = defaultWeChatConnectScopesForMode(
|
||||||
|
form.wechat_connect_mode,
|
||||||
|
);
|
||||||
form.oidc_connect_client_secret = "";
|
form.oidc_connect_client_secret = "";
|
||||||
|
|
||||||
// Load web search emulation config separately
|
// Load web search emulation config separately
|
||||||
@@ -5789,6 +5804,12 @@ async function saveSettings() {
|
|||||||
// Optional URL fields: auto-clear invalid values so they don't cause backend 400 errors
|
// Optional URL fields: auto-clear invalid values so they don't cause backend 400 errors
|
||||||
if (!isValidHttpUrl(form.frontend_url)) form.frontend_url = "";
|
if (!isValidHttpUrl(form.frontend_url)) form.frontend_url = "";
|
||||||
if (!isValidHttpUrl(form.doc_url)) form.doc_url = "";
|
if (!isValidHttpUrl(form.doc_url)) form.doc_url = "";
|
||||||
|
syncWeChatConnectMode();
|
||||||
|
const wechatStoredMode = deriveWeChatConnectStoredMode(
|
||||||
|
form.wechat_connect_open_enabled,
|
||||||
|
form.wechat_connect_mp_enabled,
|
||||||
|
form.wechat_connect_mode,
|
||||||
|
);
|
||||||
|
|
||||||
const payload: UpdateSettingsRequest = {
|
const payload: UpdateSettingsRequest = {
|
||||||
registration_enabled: form.registration_enabled,
|
registration_enabled: form.registration_enabled,
|
||||||
@@ -5837,10 +5858,11 @@ async function saveSettings() {
|
|||||||
wechat_connect_enabled: form.wechat_connect_enabled,
|
wechat_connect_enabled: form.wechat_connect_enabled,
|
||||||
wechat_connect_app_id: form.wechat_connect_app_id,
|
wechat_connect_app_id: form.wechat_connect_app_id,
|
||||||
wechat_connect_app_secret: form.wechat_connect_app_secret || undefined,
|
wechat_connect_app_secret: form.wechat_connect_app_secret || undefined,
|
||||||
wechat_connect_mode: normalizeWeChatConnectMode(form.wechat_connect_mode),
|
wechat_connect_open_enabled: form.wechat_connect_open_enabled,
|
||||||
|
wechat_connect_mp_enabled: form.wechat_connect_mp_enabled,
|
||||||
|
wechat_connect_mode: wechatStoredMode,
|
||||||
wechat_connect_scopes:
|
wechat_connect_scopes:
|
||||||
form.wechat_connect_scopes.trim() ||
|
defaultWeChatConnectScopesForMode(wechatStoredMode),
|
||||||
defaultWeChatConnectScopesForMode(form.wechat_connect_mode),
|
|
||||||
wechat_connect_redirect_url: form.wechat_connect_redirect_url,
|
wechat_connect_redirect_url: form.wechat_connect_redirect_url,
|
||||||
wechat_connect_frontend_redirect_url:
|
wechat_connect_frontend_redirect_url:
|
||||||
form.wechat_connect_frontend_redirect_url,
|
form.wechat_connect_frontend_redirect_url,
|
||||||
@@ -5967,16 +5989,21 @@ async function saveSettings() {
|
|||||||
form.turnstile_secret_key = "";
|
form.turnstile_secret_key = "";
|
||||||
form.linuxdo_connect_client_secret = "";
|
form.linuxdo_connect_client_secret = "";
|
||||||
form.wechat_connect_app_secret = "";
|
form.wechat_connect_app_secret = "";
|
||||||
form.wechat_connect_mode = normalizeWeChatConnectMode(
|
const updatedWechatCapabilities = resolveWeChatConnectModeCapabilities(
|
||||||
|
updated.wechat_connect_open_enabled,
|
||||||
|
updated.wechat_connect_mp_enabled,
|
||||||
updated.wechat_connect_mode,
|
updated.wechat_connect_mode,
|
||||||
);
|
);
|
||||||
const updatedWechatConnectScopes =
|
form.wechat_connect_open_enabled = updatedWechatCapabilities.openEnabled;
|
||||||
typeof updated.wechat_connect_scopes === "string"
|
form.wechat_connect_mp_enabled = updatedWechatCapabilities.mpEnabled;
|
||||||
? updated.wechat_connect_scopes.trim()
|
form.wechat_connect_mode = deriveWeChatConnectStoredMode(
|
||||||
: "";
|
updatedWechatCapabilities.openEnabled,
|
||||||
form.wechat_connect_scopes =
|
updatedWechatCapabilities.mpEnabled,
|
||||||
updatedWechatConnectScopes ||
|
updated.wechat_connect_mode,
|
||||||
defaultWeChatConnectScopesForMode(form.wechat_connect_mode);
|
);
|
||||||
|
form.wechat_connect_scopes = defaultWeChatConnectScopesForMode(
|
||||||
|
form.wechat_connect_mode,
|
||||||
|
);
|
||||||
form.oidc_connect_client_secret = "";
|
form.oidc_connect_client_secret = "";
|
||||||
// Save web search emulation config separately (errors handled internally)
|
// Save web search emulation config separately (errors handled internally)
|
||||||
const wsOk = await saveWebSearchConfig();
|
const wsOk = await saveWebSearchConfig();
|
||||||
|
|||||||
@@ -111,9 +111,11 @@ const ToggleStub = defineComponent({
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
emits: ["update:modelValue"],
|
emits: ["update:modelValue"],
|
||||||
setup(props, { emit }) {
|
inheritAttrs: false,
|
||||||
|
setup(props, { attrs, emit }) {
|
||||||
return () =>
|
return () =>
|
||||||
h("input", {
|
h("input", {
|
||||||
|
...attrs,
|
||||||
class: "toggle-stub",
|
class: "toggle-stub",
|
||||||
type: "checkbox",
|
type: "checkbox",
|
||||||
checked: props.modelValue,
|
checked: props.modelValue,
|
||||||
@@ -217,6 +219,8 @@ const baseSettingsResponse = {
|
|||||||
wechat_connect_enabled: true,
|
wechat_connect_enabled: true,
|
||||||
wechat_connect_app_id: "wx-app-id-123",
|
wechat_connect_app_id: "wx-app-id-123",
|
||||||
wechat_connect_app_secret_configured: true,
|
wechat_connect_app_secret_configured: true,
|
||||||
|
wechat_connect_open_enabled: false,
|
||||||
|
wechat_connect_mp_enabled: true,
|
||||||
wechat_connect_mode: "mp",
|
wechat_connect_mode: "mp",
|
||||||
wechat_connect_scopes: "",
|
wechat_connect_scopes: "",
|
||||||
wechat_connect_redirect_url:
|
wechat_connect_redirect_url:
|
||||||
@@ -334,6 +338,16 @@ async function openSecurityTab(wrapper: ReturnType<typeof mountView>) {
|
|||||||
await flushPromises();
|
await flushPromises();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function openUsersTab(wrapper: ReturnType<typeof mountView>) {
|
||||||
|
const usersTabButton = wrapper
|
||||||
|
.findAll("button")
|
||||||
|
.find((node) => node.text().includes("admin.settings.tabs.users"));
|
||||||
|
|
||||||
|
expect(usersTabButton).toBeDefined();
|
||||||
|
await usersTabButton?.trigger("click");
|
||||||
|
await flushPromises();
|
||||||
|
}
|
||||||
|
|
||||||
describe("admin SettingsView payment visible method controls", () => {
|
describe("admin SettingsView payment visible method controls", () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
getSettings.mockReset();
|
getSettings.mockReset();
|
||||||
@@ -595,16 +609,19 @@ describe("admin SettingsView wechat connect controls", () => {
|
|||||||
).toBe("wx-app-id-123");
|
).toBe("wx-app-id-123");
|
||||||
expect(
|
expect(
|
||||||
(
|
(
|
||||||
wrapper.get('[data-testid="wechat-connect-mode"]')
|
wrapper.get('[data-testid="wechat-connect-open-enabled"]')
|
||||||
.element as HTMLSelectElement
|
.element as HTMLInputElement
|
||||||
).value,
|
).checked,
|
||||||
).toBe("mp");
|
).toBe(false);
|
||||||
expect(
|
expect(
|
||||||
(
|
(
|
||||||
wrapper.get('[data-testid="wechat-connect-scopes"]')
|
wrapper.get('[data-testid="wechat-connect-mp-enabled"]')
|
||||||
.element as HTMLInputElement
|
.element as HTMLInputElement
|
||||||
).value,
|
).checked,
|
||||||
).toBe("snsapi_userinfo");
|
).toBe(true);
|
||||||
|
expect(wrapper.find('[data-testid="wechat-connect-scopes"]').exists()).toBe(
|
||||||
|
false,
|
||||||
|
);
|
||||||
expect(
|
expect(
|
||||||
wrapper
|
wrapper
|
||||||
.get('[data-testid="wechat-connect-app-secret"]')
|
.get('[data-testid="wechat-connect-app-secret"]')
|
||||||
@@ -630,10 +647,12 @@ describe("admin SettingsView wechat connect controls", () => {
|
|||||||
await wrapper
|
await wrapper
|
||||||
.get('[data-testid="wechat-connect-app-secret"]')
|
.get('[data-testid="wechat-connect-app-secret"]')
|
||||||
.setValue("new-secret");
|
.setValue("new-secret");
|
||||||
await wrapper.get('[data-testid="wechat-connect-mode"]').setValue("open");
|
|
||||||
await wrapper
|
await wrapper
|
||||||
.get('[data-testid="wechat-connect-scopes"]')
|
.get('[data-testid="wechat-connect-open-enabled"]')
|
||||||
.setValue(" snsapi_base ");
|
.setValue(true);
|
||||||
|
await wrapper
|
||||||
|
.get('[data-testid="wechat-connect-mp-enabled"]')
|
||||||
|
.setValue(true);
|
||||||
await wrapper
|
await wrapper
|
||||||
.get('[data-testid="wechat-connect-redirect-url"]')
|
.get('[data-testid="wechat-connect-redirect-url"]')
|
||||||
.setValue("https://admin.example.com/api/v1/auth/oauth/wechat/callback");
|
.setValue("https://admin.example.com/api/v1/auth/oauth/wechat/callback");
|
||||||
@@ -649,8 +668,8 @@ describe("admin SettingsView wechat connect controls", () => {
|
|||||||
wechat_connect_enabled: true,
|
wechat_connect_enabled: true,
|
||||||
wechat_connect_app_id: "wx-app-id-updated",
|
wechat_connect_app_id: "wx-app-id-updated",
|
||||||
wechat_connect_app_secret: "new-secret",
|
wechat_connect_app_secret: "new-secret",
|
||||||
wechat_connect_mode: "open",
|
wechat_connect_open_enabled: true,
|
||||||
wechat_connect_scopes: "snsapi_base",
|
wechat_connect_mp_enabled: true,
|
||||||
wechat_connect_redirect_url:
|
wechat_connect_redirect_url:
|
||||||
"https://admin.example.com/api/v1/auth/oauth/wechat/callback",
|
"https://admin.example.com/api/v1/auth/oauth/wechat/callback",
|
||||||
wechat_connect_frontend_redirect_url: "/auth/wechat/callback",
|
wechat_connect_frontend_redirect_url: "/auth/wechat/callback",
|
||||||
@@ -668,4 +687,31 @@ describe("admin SettingsView wechat connect controls", () => {
|
|||||||
.attributes("placeholder"),
|
.attributes("placeholder"),
|
||||||
).toContain("密钥已配置");
|
).toContain("密钥已配置");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("collapses auth source defaults until the source is enabled", async () => {
|
||||||
|
const wrapper = mountView();
|
||||||
|
|
||||||
|
await flushPromises();
|
||||||
|
await openUsersTab(wrapper);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
(
|
||||||
|
wrapper.get('[data-testid="auth-source-email-enabled"]')
|
||||||
|
.element as HTMLInputElement
|
||||||
|
).checked,
|
||||||
|
).toBe(false);
|
||||||
|
expect(
|
||||||
|
wrapper.find('[data-testid="auth-source-email-panel"]').exists(),
|
||||||
|
).toBe(false);
|
||||||
|
expect(wrapper.text()).not.toContain("注册即授权");
|
||||||
|
|
||||||
|
await wrapper
|
||||||
|
.get('[data-testid="auth-source-email-enabled"]')
|
||||||
|
.setValue(true);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
wrapper.find('[data-testid="auth-source-email-panel"]').exists(),
|
||||||
|
).toBe(true);
|
||||||
|
expect(wrapper.text()).toContain("首次绑定时授权");
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user