feat(settings): support per-channel WeChat OAuth and persist payment options
This commit is contained in:
@@ -43,6 +43,15 @@ func scopesContainOpenID(scopes string) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func firstNonEmpty(values ...string) string {
|
||||||
|
for _, value := range values {
|
||||||
|
if trimmed := strings.TrimSpace(value); trimmed != "" {
|
||||||
|
return trimmed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
// SettingHandler 系统设置处理器
|
// SettingHandler 系统设置处理器
|
||||||
type SettingHandler struct {
|
type SettingHandler struct {
|
||||||
settingService *service.SettingService
|
settingService *service.SettingService
|
||||||
@@ -99,126 +108,133 @@ func (h *SettingHandler) GetSettings(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
payload := dto.SystemSettings{
|
payload := dto.SystemSettings{
|
||||||
RegistrationEnabled: settings.RegistrationEnabled,
|
RegistrationEnabled: settings.RegistrationEnabled,
|
||||||
EmailVerifyEnabled: settings.EmailVerifyEnabled,
|
EmailVerifyEnabled: settings.EmailVerifyEnabled,
|
||||||
RegistrationEmailSuffixWhitelist: settings.RegistrationEmailSuffixWhitelist,
|
RegistrationEmailSuffixWhitelist: settings.RegistrationEmailSuffixWhitelist,
|
||||||
PromoCodeEnabled: settings.PromoCodeEnabled,
|
PromoCodeEnabled: settings.PromoCodeEnabled,
|
||||||
PasswordResetEnabled: settings.PasswordResetEnabled,
|
PasswordResetEnabled: settings.PasswordResetEnabled,
|
||||||
FrontendURL: settings.FrontendURL,
|
FrontendURL: settings.FrontendURL,
|
||||||
InvitationCodeEnabled: settings.InvitationCodeEnabled,
|
InvitationCodeEnabled: settings.InvitationCodeEnabled,
|
||||||
TotpEnabled: settings.TotpEnabled,
|
TotpEnabled: settings.TotpEnabled,
|
||||||
TotpEncryptionKeyConfigured: h.settingService.IsTotpEncryptionKeyConfigured(),
|
TotpEncryptionKeyConfigured: h.settingService.IsTotpEncryptionKeyConfigured(),
|
||||||
SMTPHost: settings.SMTPHost,
|
SMTPHost: settings.SMTPHost,
|
||||||
SMTPPort: settings.SMTPPort,
|
SMTPPort: settings.SMTPPort,
|
||||||
SMTPUsername: settings.SMTPUsername,
|
SMTPUsername: settings.SMTPUsername,
|
||||||
SMTPPasswordConfigured: settings.SMTPPasswordConfigured,
|
SMTPPasswordConfigured: settings.SMTPPasswordConfigured,
|
||||||
SMTPFrom: settings.SMTPFrom,
|
SMTPFrom: settings.SMTPFrom,
|
||||||
SMTPFromName: settings.SMTPFromName,
|
SMTPFromName: settings.SMTPFromName,
|
||||||
SMTPUseTLS: settings.SMTPUseTLS,
|
SMTPUseTLS: settings.SMTPUseTLS,
|
||||||
TurnstileEnabled: settings.TurnstileEnabled,
|
TurnstileEnabled: settings.TurnstileEnabled,
|
||||||
TurnstileSiteKey: settings.TurnstileSiteKey,
|
TurnstileSiteKey: settings.TurnstileSiteKey,
|
||||||
TurnstileSecretKeyConfigured: settings.TurnstileSecretKeyConfigured,
|
TurnstileSecretKeyConfigured: settings.TurnstileSecretKeyConfigured,
|
||||||
LinuxDoConnectEnabled: settings.LinuxDoConnectEnabled,
|
LinuxDoConnectEnabled: settings.LinuxDoConnectEnabled,
|
||||||
LinuxDoConnectClientID: settings.LinuxDoConnectClientID,
|
LinuxDoConnectClientID: settings.LinuxDoConnectClientID,
|
||||||
LinuxDoConnectClientSecretConfigured: settings.LinuxDoConnectClientSecretConfigured,
|
LinuxDoConnectClientSecretConfigured: settings.LinuxDoConnectClientSecretConfigured,
|
||||||
LinuxDoConnectRedirectURL: settings.LinuxDoConnectRedirectURL,
|
LinuxDoConnectRedirectURL: settings.LinuxDoConnectRedirectURL,
|
||||||
WeChatConnectEnabled: settings.WeChatConnectEnabled,
|
WeChatConnectEnabled: settings.WeChatConnectEnabled,
|
||||||
WeChatConnectAppID: settings.WeChatConnectAppID,
|
WeChatConnectAppID: settings.WeChatConnectAppID,
|
||||||
WeChatConnectAppSecretConfigured: settings.WeChatConnectAppSecretConfigured,
|
WeChatConnectAppSecretConfigured: settings.WeChatConnectAppSecretConfigured,
|
||||||
WeChatConnectOpenEnabled: settings.WeChatConnectOpenEnabled,
|
WeChatConnectOpenAppID: settings.WeChatConnectOpenAppID,
|
||||||
WeChatConnectMPEnabled: settings.WeChatConnectMPEnabled,
|
WeChatConnectOpenAppSecretConfigured: settings.WeChatConnectOpenAppSecretConfigured,
|
||||||
WeChatConnectMode: settings.WeChatConnectMode,
|
WeChatConnectMPAppID: settings.WeChatConnectMPAppID,
|
||||||
WeChatConnectScopes: settings.WeChatConnectScopes,
|
WeChatConnectMPAppSecretConfigured: settings.WeChatConnectMPAppSecretConfigured,
|
||||||
WeChatConnectRedirectURL: settings.WeChatConnectRedirectURL,
|
WeChatConnectMobileAppID: settings.WeChatConnectMobileAppID,
|
||||||
WeChatConnectFrontendRedirectURL: settings.WeChatConnectFrontendRedirectURL,
|
WeChatConnectMobileAppSecretConfigured: settings.WeChatConnectMobileAppSecretConfigured,
|
||||||
OIDCConnectEnabled: settings.OIDCConnectEnabled,
|
WeChatConnectOpenEnabled: settings.WeChatConnectOpenEnabled,
|
||||||
OIDCConnectProviderName: settings.OIDCConnectProviderName,
|
WeChatConnectMPEnabled: settings.WeChatConnectMPEnabled,
|
||||||
OIDCConnectClientID: settings.OIDCConnectClientID,
|
WeChatConnectMobileEnabled: settings.WeChatConnectMobileEnabled,
|
||||||
OIDCConnectClientSecretConfigured: settings.OIDCConnectClientSecretConfigured,
|
WeChatConnectMode: settings.WeChatConnectMode,
|
||||||
OIDCConnectIssuerURL: settings.OIDCConnectIssuerURL,
|
WeChatConnectScopes: settings.WeChatConnectScopes,
|
||||||
OIDCConnectDiscoveryURL: settings.OIDCConnectDiscoveryURL,
|
WeChatConnectRedirectURL: settings.WeChatConnectRedirectURL,
|
||||||
OIDCConnectAuthorizeURL: settings.OIDCConnectAuthorizeURL,
|
WeChatConnectFrontendRedirectURL: settings.WeChatConnectFrontendRedirectURL,
|
||||||
OIDCConnectTokenURL: settings.OIDCConnectTokenURL,
|
OIDCConnectEnabled: settings.OIDCConnectEnabled,
|
||||||
OIDCConnectUserInfoURL: settings.OIDCConnectUserInfoURL,
|
OIDCConnectProviderName: settings.OIDCConnectProviderName,
|
||||||
OIDCConnectJWKSURL: settings.OIDCConnectJWKSURL,
|
OIDCConnectClientID: settings.OIDCConnectClientID,
|
||||||
OIDCConnectScopes: settings.OIDCConnectScopes,
|
OIDCConnectClientSecretConfigured: settings.OIDCConnectClientSecretConfigured,
|
||||||
OIDCConnectRedirectURL: settings.OIDCConnectRedirectURL,
|
OIDCConnectIssuerURL: settings.OIDCConnectIssuerURL,
|
||||||
OIDCConnectFrontendRedirectURL: settings.OIDCConnectFrontendRedirectURL,
|
OIDCConnectDiscoveryURL: settings.OIDCConnectDiscoveryURL,
|
||||||
OIDCConnectTokenAuthMethod: settings.OIDCConnectTokenAuthMethod,
|
OIDCConnectAuthorizeURL: settings.OIDCConnectAuthorizeURL,
|
||||||
OIDCConnectUsePKCE: settings.OIDCConnectUsePKCE,
|
OIDCConnectTokenURL: settings.OIDCConnectTokenURL,
|
||||||
OIDCConnectValidateIDToken: settings.OIDCConnectValidateIDToken,
|
OIDCConnectUserInfoURL: settings.OIDCConnectUserInfoURL,
|
||||||
OIDCConnectAllowedSigningAlgs: settings.OIDCConnectAllowedSigningAlgs,
|
OIDCConnectJWKSURL: settings.OIDCConnectJWKSURL,
|
||||||
OIDCConnectClockSkewSeconds: settings.OIDCConnectClockSkewSeconds,
|
OIDCConnectScopes: settings.OIDCConnectScopes,
|
||||||
OIDCConnectRequireEmailVerified: settings.OIDCConnectRequireEmailVerified,
|
OIDCConnectRedirectURL: settings.OIDCConnectRedirectURL,
|
||||||
OIDCConnectUserInfoEmailPath: settings.OIDCConnectUserInfoEmailPath,
|
OIDCConnectFrontendRedirectURL: settings.OIDCConnectFrontendRedirectURL,
|
||||||
OIDCConnectUserInfoIDPath: settings.OIDCConnectUserInfoIDPath,
|
OIDCConnectTokenAuthMethod: settings.OIDCConnectTokenAuthMethod,
|
||||||
OIDCConnectUserInfoUsernamePath: settings.OIDCConnectUserInfoUsernamePath,
|
OIDCConnectUsePKCE: settings.OIDCConnectUsePKCE,
|
||||||
SiteName: settings.SiteName,
|
OIDCConnectValidateIDToken: settings.OIDCConnectValidateIDToken,
|
||||||
SiteLogo: settings.SiteLogo,
|
OIDCConnectAllowedSigningAlgs: settings.OIDCConnectAllowedSigningAlgs,
|
||||||
SiteSubtitle: settings.SiteSubtitle,
|
OIDCConnectClockSkewSeconds: settings.OIDCConnectClockSkewSeconds,
|
||||||
APIBaseURL: settings.APIBaseURL,
|
OIDCConnectRequireEmailVerified: settings.OIDCConnectRequireEmailVerified,
|
||||||
ContactInfo: settings.ContactInfo,
|
OIDCConnectUserInfoEmailPath: settings.OIDCConnectUserInfoEmailPath,
|
||||||
DocURL: settings.DocURL,
|
OIDCConnectUserInfoIDPath: settings.OIDCConnectUserInfoIDPath,
|
||||||
HomeContent: settings.HomeContent,
|
OIDCConnectUserInfoUsernamePath: settings.OIDCConnectUserInfoUsernamePath,
|
||||||
HideCcsImportButton: settings.HideCcsImportButton,
|
SiteName: settings.SiteName,
|
||||||
PurchaseSubscriptionEnabled: settings.PurchaseSubscriptionEnabled,
|
SiteLogo: settings.SiteLogo,
|
||||||
PurchaseSubscriptionURL: settings.PurchaseSubscriptionURL,
|
SiteSubtitle: settings.SiteSubtitle,
|
||||||
TableDefaultPageSize: settings.TableDefaultPageSize,
|
APIBaseURL: settings.APIBaseURL,
|
||||||
TablePageSizeOptions: settings.TablePageSizeOptions,
|
ContactInfo: settings.ContactInfo,
|
||||||
CustomMenuItems: dto.ParseCustomMenuItems(settings.CustomMenuItems),
|
DocURL: settings.DocURL,
|
||||||
CustomEndpoints: dto.ParseCustomEndpoints(settings.CustomEndpoints),
|
HomeContent: settings.HomeContent,
|
||||||
DefaultConcurrency: settings.DefaultConcurrency,
|
HideCcsImportButton: settings.HideCcsImportButton,
|
||||||
DefaultBalance: settings.DefaultBalance,
|
PurchaseSubscriptionEnabled: settings.PurchaseSubscriptionEnabled,
|
||||||
DefaultSubscriptions: defaultSubscriptions,
|
PurchaseSubscriptionURL: settings.PurchaseSubscriptionURL,
|
||||||
EnableModelFallback: settings.EnableModelFallback,
|
TableDefaultPageSize: settings.TableDefaultPageSize,
|
||||||
FallbackModelAnthropic: settings.FallbackModelAnthropic,
|
TablePageSizeOptions: settings.TablePageSizeOptions,
|
||||||
FallbackModelOpenAI: settings.FallbackModelOpenAI,
|
CustomMenuItems: dto.ParseCustomMenuItems(settings.CustomMenuItems),
|
||||||
FallbackModelGemini: settings.FallbackModelGemini,
|
CustomEndpoints: dto.ParseCustomEndpoints(settings.CustomEndpoints),
|
||||||
FallbackModelAntigravity: settings.FallbackModelAntigravity,
|
DefaultConcurrency: settings.DefaultConcurrency,
|
||||||
EnableIdentityPatch: settings.EnableIdentityPatch,
|
DefaultBalance: settings.DefaultBalance,
|
||||||
IdentityPatchPrompt: settings.IdentityPatchPrompt,
|
DefaultSubscriptions: defaultSubscriptions,
|
||||||
OpsMonitoringEnabled: opsEnabled && settings.OpsMonitoringEnabled,
|
EnableModelFallback: settings.EnableModelFallback,
|
||||||
OpsRealtimeMonitoringEnabled: settings.OpsRealtimeMonitoringEnabled,
|
FallbackModelAnthropic: settings.FallbackModelAnthropic,
|
||||||
OpsQueryModeDefault: settings.OpsQueryModeDefault,
|
FallbackModelOpenAI: settings.FallbackModelOpenAI,
|
||||||
OpsMetricsIntervalSeconds: settings.OpsMetricsIntervalSeconds,
|
FallbackModelGemini: settings.FallbackModelGemini,
|
||||||
MinClaudeCodeVersion: settings.MinClaudeCodeVersion,
|
FallbackModelAntigravity: settings.FallbackModelAntigravity,
|
||||||
MaxClaudeCodeVersion: settings.MaxClaudeCodeVersion,
|
EnableIdentityPatch: settings.EnableIdentityPatch,
|
||||||
AllowUngroupedKeyScheduling: settings.AllowUngroupedKeyScheduling,
|
IdentityPatchPrompt: settings.IdentityPatchPrompt,
|
||||||
BackendModeEnabled: settings.BackendModeEnabled,
|
OpsMonitoringEnabled: opsEnabled && settings.OpsMonitoringEnabled,
|
||||||
EnableFingerprintUnification: settings.EnableFingerprintUnification,
|
OpsRealtimeMonitoringEnabled: settings.OpsRealtimeMonitoringEnabled,
|
||||||
EnableMetadataPassthrough: settings.EnableMetadataPassthrough,
|
OpsQueryModeDefault: settings.OpsQueryModeDefault,
|
||||||
EnableCCHSigning: settings.EnableCCHSigning,
|
OpsMetricsIntervalSeconds: settings.OpsMetricsIntervalSeconds,
|
||||||
WebSearchEmulationEnabled: settings.WebSearchEmulationEnabled,
|
MinClaudeCodeVersion: settings.MinClaudeCodeVersion,
|
||||||
PaymentVisibleMethodAlipaySource: settings.PaymentVisibleMethodAlipaySource,
|
MaxClaudeCodeVersion: settings.MaxClaudeCodeVersion,
|
||||||
PaymentVisibleMethodWxpaySource: settings.PaymentVisibleMethodWxpaySource,
|
AllowUngroupedKeyScheduling: settings.AllowUngroupedKeyScheduling,
|
||||||
PaymentVisibleMethodAlipayEnabled: settings.PaymentVisibleMethodAlipayEnabled,
|
BackendModeEnabled: settings.BackendModeEnabled,
|
||||||
PaymentVisibleMethodWxpayEnabled: settings.PaymentVisibleMethodWxpayEnabled,
|
EnableFingerprintUnification: settings.EnableFingerprintUnification,
|
||||||
OpenAIAdvancedSchedulerEnabled: settings.OpenAIAdvancedSchedulerEnabled,
|
EnableMetadataPassthrough: settings.EnableMetadataPassthrough,
|
||||||
BalanceLowNotifyEnabled: settings.BalanceLowNotifyEnabled,
|
EnableCCHSigning: settings.EnableCCHSigning,
|
||||||
BalanceLowNotifyThreshold: settings.BalanceLowNotifyThreshold,
|
WebSearchEmulationEnabled: settings.WebSearchEmulationEnabled,
|
||||||
BalanceLowNotifyRechargeURL: settings.BalanceLowNotifyRechargeURL,
|
PaymentVisibleMethodAlipaySource: settings.PaymentVisibleMethodAlipaySource,
|
||||||
AccountQuotaNotifyEnabled: settings.AccountQuotaNotifyEnabled,
|
PaymentVisibleMethodWxpaySource: settings.PaymentVisibleMethodWxpaySource,
|
||||||
AccountQuotaNotifyEmails: dto.NotifyEmailEntriesFromService(settings.AccountQuotaNotifyEmails),
|
PaymentVisibleMethodAlipayEnabled: settings.PaymentVisibleMethodAlipayEnabled,
|
||||||
PaymentEnabled: paymentCfg.Enabled,
|
PaymentVisibleMethodWxpayEnabled: settings.PaymentVisibleMethodWxpayEnabled,
|
||||||
PaymentMinAmount: paymentCfg.MinAmount,
|
OpenAIAdvancedSchedulerEnabled: settings.OpenAIAdvancedSchedulerEnabled,
|
||||||
PaymentMaxAmount: paymentCfg.MaxAmount,
|
BalanceLowNotifyEnabled: settings.BalanceLowNotifyEnabled,
|
||||||
PaymentDailyLimit: paymentCfg.DailyLimit,
|
BalanceLowNotifyThreshold: settings.BalanceLowNotifyThreshold,
|
||||||
PaymentOrderTimeoutMin: paymentCfg.OrderTimeoutMin,
|
BalanceLowNotifyRechargeURL: settings.BalanceLowNotifyRechargeURL,
|
||||||
PaymentMaxPendingOrders: paymentCfg.MaxPendingOrders,
|
AccountQuotaNotifyEnabled: settings.AccountQuotaNotifyEnabled,
|
||||||
PaymentEnabledTypes: paymentCfg.EnabledTypes,
|
AccountQuotaNotifyEmails: dto.NotifyEmailEntriesFromService(settings.AccountQuotaNotifyEmails),
|
||||||
PaymentBalanceDisabled: paymentCfg.BalanceDisabled,
|
PaymentEnabled: paymentCfg.Enabled,
|
||||||
PaymentBalanceRechargeMultiplier: paymentCfg.BalanceRechargeMultiplier,
|
PaymentMinAmount: paymentCfg.MinAmount,
|
||||||
PaymentRechargeFeeRate: paymentCfg.RechargeFeeRate,
|
PaymentMaxAmount: paymentCfg.MaxAmount,
|
||||||
PaymentLoadBalanceStrat: paymentCfg.LoadBalanceStrategy,
|
PaymentDailyLimit: paymentCfg.DailyLimit,
|
||||||
PaymentProductNamePrefix: paymentCfg.ProductNamePrefix,
|
PaymentOrderTimeoutMin: paymentCfg.OrderTimeoutMin,
|
||||||
PaymentProductNameSuffix: paymentCfg.ProductNameSuffix,
|
PaymentMaxPendingOrders: paymentCfg.MaxPendingOrders,
|
||||||
PaymentHelpImageURL: paymentCfg.HelpImageURL,
|
PaymentEnabledTypes: paymentCfg.EnabledTypes,
|
||||||
PaymentHelpText: paymentCfg.HelpText,
|
PaymentBalanceDisabled: paymentCfg.BalanceDisabled,
|
||||||
PaymentCancelRateLimitEnabled: paymentCfg.CancelRateLimitEnabled,
|
PaymentBalanceRechargeMultiplier: paymentCfg.BalanceRechargeMultiplier,
|
||||||
PaymentCancelRateLimitMax: paymentCfg.CancelRateLimitMax,
|
PaymentRechargeFeeRate: paymentCfg.RechargeFeeRate,
|
||||||
PaymentCancelRateLimitWindow: paymentCfg.CancelRateLimitWindow,
|
PaymentLoadBalanceStrat: paymentCfg.LoadBalanceStrategy,
|
||||||
PaymentCancelRateLimitUnit: paymentCfg.CancelRateLimitUnit,
|
PaymentProductNamePrefix: paymentCfg.ProductNamePrefix,
|
||||||
PaymentCancelRateLimitMode: paymentCfg.CancelRateLimitMode,
|
PaymentProductNameSuffix: paymentCfg.ProductNameSuffix,
|
||||||
|
PaymentHelpImageURL: paymentCfg.HelpImageURL,
|
||||||
|
PaymentHelpText: paymentCfg.HelpText,
|
||||||
|
PaymentCancelRateLimitEnabled: paymentCfg.CancelRateLimitEnabled,
|
||||||
|
PaymentCancelRateLimitMax: paymentCfg.CancelRateLimitMax,
|
||||||
|
PaymentCancelRateLimitWindow: paymentCfg.CancelRateLimitWindow,
|
||||||
|
PaymentCancelRateLimitUnit: paymentCfg.CancelRateLimitUnit,
|
||||||
|
PaymentCancelRateLimitMode: paymentCfg.CancelRateLimitMode,
|
||||||
}
|
}
|
||||||
response.Success(c, systemSettingsResponseData(payload, authSourceDefaults))
|
response.Success(c, systemSettingsResponseData(payload, authSourceDefaults))
|
||||||
}
|
}
|
||||||
@@ -259,8 +275,15 @@ 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"`
|
||||||
|
WeChatConnectOpenAppID string `json:"wechat_connect_open_app_id"`
|
||||||
|
WeChatConnectOpenAppSecret string `json:"wechat_connect_open_app_secret"`
|
||||||
|
WeChatConnectMPAppID string `json:"wechat_connect_mp_app_id"`
|
||||||
|
WeChatConnectMPAppSecret string `json:"wechat_connect_mp_app_secret"`
|
||||||
|
WeChatConnectMobileAppID string `json:"wechat_connect_mobile_app_id"`
|
||||||
|
WeChatConnectMobileAppSecret string `json:"wechat_connect_mobile_app_secret"`
|
||||||
WeChatConnectOpenEnabled bool `json:"wechat_connect_open_enabled"`
|
WeChatConnectOpenEnabled bool `json:"wechat_connect_open_enabled"`
|
||||||
WeChatConnectMPEnabled bool `json:"wechat_connect_mp_enabled"`
|
WeChatConnectMPEnabled bool `json:"wechat_connect_mp_enabled"`
|
||||||
|
WeChatConnectMobileEnabled bool `json:"wechat_connect_mobile_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"`
|
||||||
@@ -532,34 +555,35 @@ func (h *SettingHandler) UpdateSettings(c *gin.Context) {
|
|||||||
if req.WeChatConnectEnabled {
|
if req.WeChatConnectEnabled {
|
||||||
req.WeChatConnectAppID = strings.TrimSpace(req.WeChatConnectAppID)
|
req.WeChatConnectAppID = strings.TrimSpace(req.WeChatConnectAppID)
|
||||||
req.WeChatConnectAppSecret = strings.TrimSpace(req.WeChatConnectAppSecret)
|
req.WeChatConnectAppSecret = strings.TrimSpace(req.WeChatConnectAppSecret)
|
||||||
|
req.WeChatConnectOpenAppID = strings.TrimSpace(req.WeChatConnectOpenAppID)
|
||||||
|
req.WeChatConnectOpenAppSecret = strings.TrimSpace(req.WeChatConnectOpenAppSecret)
|
||||||
|
req.WeChatConnectMPAppID = strings.TrimSpace(req.WeChatConnectMPAppID)
|
||||||
|
req.WeChatConnectMPAppSecret = strings.TrimSpace(req.WeChatConnectMPAppSecret)
|
||||||
|
req.WeChatConnectMobileAppID = strings.TrimSpace(req.WeChatConnectMobileAppID)
|
||||||
|
req.WeChatConnectMobileAppSecret = strings.TrimSpace(req.WeChatConnectMobileAppSecret)
|
||||||
req.WeChatConnectMode = strings.ToLower(strings.TrimSpace(req.WeChatConnectMode))
|
req.WeChatConnectMode = strings.ToLower(strings.TrimSpace(req.WeChatConnectMode))
|
||||||
req.WeChatConnectScopes = strings.TrimSpace(req.WeChatConnectScopes)
|
req.WeChatConnectScopes = strings.TrimSpace(req.WeChatConnectScopes)
|
||||||
req.WeChatConnectRedirectURL = strings.TrimSpace(req.WeChatConnectRedirectURL)
|
req.WeChatConnectRedirectURL = strings.TrimSpace(req.WeChatConnectRedirectURL)
|
||||||
req.WeChatConnectFrontendRedirectURL = strings.TrimSpace(req.WeChatConnectFrontendRedirectURL)
|
req.WeChatConnectFrontendRedirectURL = strings.TrimSpace(req.WeChatConnectFrontendRedirectURL)
|
||||||
|
|
||||||
if req.WeChatConnectAppID == "" {
|
if req.WeChatConnectMPEnabled && req.WeChatConnectMobileEnabled {
|
||||||
response.BadRequest(c, "WeChat App ID is required when enabled")
|
response.BadRequest(c, "WeChat Official Account and Mobile App cannot be enabled at the same time")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if req.WeChatConnectAppSecret == "" {
|
|
||||||
if previousSettings.WeChatConnectAppSecret == "" {
|
|
||||||
response.BadRequest(c, "WeChat App Secret is required when enabled")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
req.WeChatConnectAppSecret = previousSettings.WeChatConnectAppSecret
|
|
||||||
}
|
|
||||||
if req.WeChatConnectMode != "" {
|
if req.WeChatConnectMode != "" {
|
||||||
switch req.WeChatConnectMode {
|
switch req.WeChatConnectMode {
|
||||||
case "open", "mp":
|
case "open", "mp", "mobile":
|
||||||
default:
|
default:
|
||||||
response.BadRequest(c, "WeChat mode must be open or mp")
|
response.BadRequest(c, "WeChat mode must be open, mp, or mobile")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !req.WeChatConnectOpenEnabled && !req.WeChatConnectMPEnabled {
|
if !req.WeChatConnectOpenEnabled && !req.WeChatConnectMPEnabled && !req.WeChatConnectMobileEnabled {
|
||||||
switch req.WeChatConnectMode {
|
switch req.WeChatConnectMode {
|
||||||
case "mp":
|
case "mp":
|
||||||
req.WeChatConnectMPEnabled = true
|
req.WeChatConnectMPEnabled = true
|
||||||
|
case "mobile":
|
||||||
|
req.WeChatConnectMobileEnabled = true
|
||||||
default:
|
default:
|
||||||
req.WeChatConnectOpenEnabled = true
|
req.WeChatConnectOpenEnabled = true
|
||||||
}
|
}
|
||||||
@@ -567,10 +591,61 @@ func (h *SettingHandler) UpdateSettings(c *gin.Context) {
|
|||||||
if req.WeChatConnectMode == "" {
|
if req.WeChatConnectMode == "" {
|
||||||
if req.WeChatConnectMPEnabled {
|
if req.WeChatConnectMPEnabled {
|
||||||
req.WeChatConnectMode = "mp"
|
req.WeChatConnectMode = "mp"
|
||||||
|
} else if req.WeChatConnectMobileEnabled {
|
||||||
|
req.WeChatConnectMode = "mobile"
|
||||||
} else {
|
} else {
|
||||||
req.WeChatConnectMode = "open"
|
req.WeChatConnectMode = "open"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
req.WeChatConnectOpenAppID = strings.TrimSpace(firstNonEmpty(req.WeChatConnectOpenAppID, req.WeChatConnectAppID))
|
||||||
|
req.WeChatConnectMPAppID = strings.TrimSpace(firstNonEmpty(req.WeChatConnectMPAppID, req.WeChatConnectAppID))
|
||||||
|
req.WeChatConnectMobileAppID = strings.TrimSpace(firstNonEmpty(req.WeChatConnectMobileAppID, req.WeChatConnectAppID))
|
||||||
|
|
||||||
|
if req.WeChatConnectOpenAppSecret == "" {
|
||||||
|
req.WeChatConnectOpenAppSecret = strings.TrimSpace(firstNonEmpty(previousSettings.WeChatConnectOpenAppSecret, previousSettings.WeChatConnectAppSecret, req.WeChatConnectAppSecret))
|
||||||
|
}
|
||||||
|
if req.WeChatConnectMPAppSecret == "" {
|
||||||
|
req.WeChatConnectMPAppSecret = strings.TrimSpace(firstNonEmpty(previousSettings.WeChatConnectMPAppSecret, previousSettings.WeChatConnectAppSecret, req.WeChatConnectAppSecret))
|
||||||
|
}
|
||||||
|
if req.WeChatConnectMobileAppSecret == "" {
|
||||||
|
req.WeChatConnectMobileAppSecret = strings.TrimSpace(firstNonEmpty(previousSettings.WeChatConnectMobileAppSecret, previousSettings.WeChatConnectAppSecret, req.WeChatConnectAppSecret))
|
||||||
|
}
|
||||||
|
if req.WeChatConnectAppSecret == "" {
|
||||||
|
req.WeChatConnectAppSecret = strings.TrimSpace(firstNonEmpty(req.WeChatConnectOpenAppSecret, req.WeChatConnectMPAppSecret, req.WeChatConnectMobileAppSecret, previousSettings.WeChatConnectAppSecret))
|
||||||
|
}
|
||||||
|
|
||||||
|
if req.WeChatConnectOpenEnabled {
|
||||||
|
if req.WeChatConnectOpenAppID == "" {
|
||||||
|
response.BadRequest(c, "WeChat PC App ID is required when enabled")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if req.WeChatConnectOpenAppSecret == "" {
|
||||||
|
response.BadRequest(c, "WeChat PC App Secret is required when enabled")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if req.WeChatConnectMPEnabled {
|
||||||
|
if req.WeChatConnectMPAppID == "" {
|
||||||
|
response.BadRequest(c, "WeChat Official Account App ID is required when enabled")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if req.WeChatConnectMPAppSecret == "" {
|
||||||
|
response.BadRequest(c, "WeChat Official Account App Secret is required when enabled")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if req.WeChatConnectMobileEnabled {
|
||||||
|
if req.WeChatConnectMobileAppID == "" {
|
||||||
|
response.BadRequest(c, "WeChat Mobile App ID is required when enabled")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if req.WeChatConnectMobileAppSecret == "" {
|
||||||
|
response.BadRequest(c, "WeChat Mobile App Secret is required when enabled")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if req.WeChatConnectScopes == "" {
|
if req.WeChatConnectScopes == "" {
|
||||||
if req.WeChatConnectMPEnabled {
|
if req.WeChatConnectMPEnabled {
|
||||||
req.WeChatConnectScopes = service.DefaultWeChatConnectScopesForMode("mp")
|
req.WeChatConnectScopes = service.DefaultWeChatConnectScopesForMode("mp")
|
||||||
@@ -946,8 +1021,15 @@ 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,
|
||||||
|
WeChatConnectOpenAppID: req.WeChatConnectOpenAppID,
|
||||||
|
WeChatConnectOpenAppSecret: req.WeChatConnectOpenAppSecret,
|
||||||
|
WeChatConnectMPAppID: req.WeChatConnectMPAppID,
|
||||||
|
WeChatConnectMPAppSecret: req.WeChatConnectMPAppSecret,
|
||||||
|
WeChatConnectMobileAppID: req.WeChatConnectMobileAppID,
|
||||||
|
WeChatConnectMobileAppSecret: req.WeChatConnectMobileAppSecret,
|
||||||
WeChatConnectOpenEnabled: req.WeChatConnectOpenEnabled,
|
WeChatConnectOpenEnabled: req.WeChatConnectOpenEnabled,
|
||||||
WeChatConnectMPEnabled: req.WeChatConnectMPEnabled,
|
WeChatConnectMPEnabled: req.WeChatConnectMPEnabled,
|
||||||
|
WeChatConnectMobileEnabled: req.WeChatConnectMobileEnabled,
|
||||||
WeChatConnectMode: req.WeChatConnectMode,
|
WeChatConnectMode: req.WeChatConnectMode,
|
||||||
WeChatConnectScopes: req.WeChatConnectScopes,
|
WeChatConnectScopes: req.WeChatConnectScopes,
|
||||||
WeChatConnectRedirectURL: req.WeChatConnectRedirectURL,
|
WeChatConnectRedirectURL: req.WeChatConnectRedirectURL,
|
||||||
@@ -1208,125 +1290,132 @@ func (h *SettingHandler) UpdateSettings(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
payload := dto.SystemSettings{
|
payload := dto.SystemSettings{
|
||||||
RegistrationEnabled: updatedSettings.RegistrationEnabled,
|
RegistrationEnabled: updatedSettings.RegistrationEnabled,
|
||||||
EmailVerifyEnabled: updatedSettings.EmailVerifyEnabled,
|
EmailVerifyEnabled: updatedSettings.EmailVerifyEnabled,
|
||||||
RegistrationEmailSuffixWhitelist: updatedSettings.RegistrationEmailSuffixWhitelist,
|
RegistrationEmailSuffixWhitelist: updatedSettings.RegistrationEmailSuffixWhitelist,
|
||||||
PromoCodeEnabled: updatedSettings.PromoCodeEnabled,
|
PromoCodeEnabled: updatedSettings.PromoCodeEnabled,
|
||||||
PasswordResetEnabled: updatedSettings.PasswordResetEnabled,
|
PasswordResetEnabled: updatedSettings.PasswordResetEnabled,
|
||||||
FrontendURL: updatedSettings.FrontendURL,
|
FrontendURL: updatedSettings.FrontendURL,
|
||||||
InvitationCodeEnabled: updatedSettings.InvitationCodeEnabled,
|
InvitationCodeEnabled: updatedSettings.InvitationCodeEnabled,
|
||||||
TotpEnabled: updatedSettings.TotpEnabled,
|
TotpEnabled: updatedSettings.TotpEnabled,
|
||||||
TotpEncryptionKeyConfigured: h.settingService.IsTotpEncryptionKeyConfigured(),
|
TotpEncryptionKeyConfigured: h.settingService.IsTotpEncryptionKeyConfigured(),
|
||||||
SMTPHost: updatedSettings.SMTPHost,
|
SMTPHost: updatedSettings.SMTPHost,
|
||||||
SMTPPort: updatedSettings.SMTPPort,
|
SMTPPort: updatedSettings.SMTPPort,
|
||||||
SMTPUsername: updatedSettings.SMTPUsername,
|
SMTPUsername: updatedSettings.SMTPUsername,
|
||||||
SMTPPasswordConfigured: updatedSettings.SMTPPasswordConfigured,
|
SMTPPasswordConfigured: updatedSettings.SMTPPasswordConfigured,
|
||||||
SMTPFrom: updatedSettings.SMTPFrom,
|
SMTPFrom: updatedSettings.SMTPFrom,
|
||||||
SMTPFromName: updatedSettings.SMTPFromName,
|
SMTPFromName: updatedSettings.SMTPFromName,
|
||||||
SMTPUseTLS: updatedSettings.SMTPUseTLS,
|
SMTPUseTLS: updatedSettings.SMTPUseTLS,
|
||||||
TurnstileEnabled: updatedSettings.TurnstileEnabled,
|
TurnstileEnabled: updatedSettings.TurnstileEnabled,
|
||||||
TurnstileSiteKey: updatedSettings.TurnstileSiteKey,
|
TurnstileSiteKey: updatedSettings.TurnstileSiteKey,
|
||||||
TurnstileSecretKeyConfigured: updatedSettings.TurnstileSecretKeyConfigured,
|
TurnstileSecretKeyConfigured: updatedSettings.TurnstileSecretKeyConfigured,
|
||||||
LinuxDoConnectEnabled: updatedSettings.LinuxDoConnectEnabled,
|
LinuxDoConnectEnabled: updatedSettings.LinuxDoConnectEnabled,
|
||||||
LinuxDoConnectClientID: updatedSettings.LinuxDoConnectClientID,
|
LinuxDoConnectClientID: updatedSettings.LinuxDoConnectClientID,
|
||||||
LinuxDoConnectClientSecretConfigured: updatedSettings.LinuxDoConnectClientSecretConfigured,
|
LinuxDoConnectClientSecretConfigured: updatedSettings.LinuxDoConnectClientSecretConfigured,
|
||||||
LinuxDoConnectRedirectURL: updatedSettings.LinuxDoConnectRedirectURL,
|
LinuxDoConnectRedirectURL: updatedSettings.LinuxDoConnectRedirectURL,
|
||||||
WeChatConnectEnabled: updatedSettings.WeChatConnectEnabled,
|
WeChatConnectEnabled: updatedSettings.WeChatConnectEnabled,
|
||||||
WeChatConnectAppID: updatedSettings.WeChatConnectAppID,
|
WeChatConnectAppID: updatedSettings.WeChatConnectAppID,
|
||||||
WeChatConnectAppSecretConfigured: updatedSettings.WeChatConnectAppSecretConfigured,
|
WeChatConnectAppSecretConfigured: updatedSettings.WeChatConnectAppSecretConfigured,
|
||||||
WeChatConnectOpenEnabled: updatedSettings.WeChatConnectOpenEnabled,
|
WeChatConnectOpenAppID: updatedSettings.WeChatConnectOpenAppID,
|
||||||
WeChatConnectMPEnabled: updatedSettings.WeChatConnectMPEnabled,
|
WeChatConnectOpenAppSecretConfigured: updatedSettings.WeChatConnectOpenAppSecretConfigured,
|
||||||
WeChatConnectMode: updatedSettings.WeChatConnectMode,
|
WeChatConnectMPAppID: updatedSettings.WeChatConnectMPAppID,
|
||||||
WeChatConnectScopes: updatedSettings.WeChatConnectScopes,
|
WeChatConnectMPAppSecretConfigured: updatedSettings.WeChatConnectMPAppSecretConfigured,
|
||||||
WeChatConnectRedirectURL: updatedSettings.WeChatConnectRedirectURL,
|
WeChatConnectMobileAppID: updatedSettings.WeChatConnectMobileAppID,
|
||||||
WeChatConnectFrontendRedirectURL: updatedSettings.WeChatConnectFrontendRedirectURL,
|
WeChatConnectMobileAppSecretConfigured: updatedSettings.WeChatConnectMobileAppSecretConfigured,
|
||||||
OIDCConnectEnabled: updatedSettings.OIDCConnectEnabled,
|
WeChatConnectOpenEnabled: updatedSettings.WeChatConnectOpenEnabled,
|
||||||
OIDCConnectProviderName: updatedSettings.OIDCConnectProviderName,
|
WeChatConnectMPEnabled: updatedSettings.WeChatConnectMPEnabled,
|
||||||
OIDCConnectClientID: updatedSettings.OIDCConnectClientID,
|
WeChatConnectMobileEnabled: updatedSettings.WeChatConnectMobileEnabled,
|
||||||
OIDCConnectClientSecretConfigured: updatedSettings.OIDCConnectClientSecretConfigured,
|
WeChatConnectMode: updatedSettings.WeChatConnectMode,
|
||||||
OIDCConnectIssuerURL: updatedSettings.OIDCConnectIssuerURL,
|
WeChatConnectScopes: updatedSettings.WeChatConnectScopes,
|
||||||
OIDCConnectDiscoveryURL: updatedSettings.OIDCConnectDiscoveryURL,
|
WeChatConnectRedirectURL: updatedSettings.WeChatConnectRedirectURL,
|
||||||
OIDCConnectAuthorizeURL: updatedSettings.OIDCConnectAuthorizeURL,
|
WeChatConnectFrontendRedirectURL: updatedSettings.WeChatConnectFrontendRedirectURL,
|
||||||
OIDCConnectTokenURL: updatedSettings.OIDCConnectTokenURL,
|
OIDCConnectEnabled: updatedSettings.OIDCConnectEnabled,
|
||||||
OIDCConnectUserInfoURL: updatedSettings.OIDCConnectUserInfoURL,
|
OIDCConnectProviderName: updatedSettings.OIDCConnectProviderName,
|
||||||
OIDCConnectJWKSURL: updatedSettings.OIDCConnectJWKSURL,
|
OIDCConnectClientID: updatedSettings.OIDCConnectClientID,
|
||||||
OIDCConnectScopes: updatedSettings.OIDCConnectScopes,
|
OIDCConnectClientSecretConfigured: updatedSettings.OIDCConnectClientSecretConfigured,
|
||||||
OIDCConnectRedirectURL: updatedSettings.OIDCConnectRedirectURL,
|
OIDCConnectIssuerURL: updatedSettings.OIDCConnectIssuerURL,
|
||||||
OIDCConnectFrontendRedirectURL: updatedSettings.OIDCConnectFrontendRedirectURL,
|
OIDCConnectDiscoveryURL: updatedSettings.OIDCConnectDiscoveryURL,
|
||||||
OIDCConnectTokenAuthMethod: updatedSettings.OIDCConnectTokenAuthMethod,
|
OIDCConnectAuthorizeURL: updatedSettings.OIDCConnectAuthorizeURL,
|
||||||
OIDCConnectUsePKCE: updatedSettings.OIDCConnectUsePKCE,
|
OIDCConnectTokenURL: updatedSettings.OIDCConnectTokenURL,
|
||||||
OIDCConnectValidateIDToken: updatedSettings.OIDCConnectValidateIDToken,
|
OIDCConnectUserInfoURL: updatedSettings.OIDCConnectUserInfoURL,
|
||||||
OIDCConnectAllowedSigningAlgs: updatedSettings.OIDCConnectAllowedSigningAlgs,
|
OIDCConnectJWKSURL: updatedSettings.OIDCConnectJWKSURL,
|
||||||
OIDCConnectClockSkewSeconds: updatedSettings.OIDCConnectClockSkewSeconds,
|
OIDCConnectScopes: updatedSettings.OIDCConnectScopes,
|
||||||
OIDCConnectRequireEmailVerified: updatedSettings.OIDCConnectRequireEmailVerified,
|
OIDCConnectRedirectURL: updatedSettings.OIDCConnectRedirectURL,
|
||||||
OIDCConnectUserInfoEmailPath: updatedSettings.OIDCConnectUserInfoEmailPath,
|
OIDCConnectFrontendRedirectURL: updatedSettings.OIDCConnectFrontendRedirectURL,
|
||||||
OIDCConnectUserInfoIDPath: updatedSettings.OIDCConnectUserInfoIDPath,
|
OIDCConnectTokenAuthMethod: updatedSettings.OIDCConnectTokenAuthMethod,
|
||||||
OIDCConnectUserInfoUsernamePath: updatedSettings.OIDCConnectUserInfoUsernamePath,
|
OIDCConnectUsePKCE: updatedSettings.OIDCConnectUsePKCE,
|
||||||
SiteName: updatedSettings.SiteName,
|
OIDCConnectValidateIDToken: updatedSettings.OIDCConnectValidateIDToken,
|
||||||
SiteLogo: updatedSettings.SiteLogo,
|
OIDCConnectAllowedSigningAlgs: updatedSettings.OIDCConnectAllowedSigningAlgs,
|
||||||
SiteSubtitle: updatedSettings.SiteSubtitle,
|
OIDCConnectClockSkewSeconds: updatedSettings.OIDCConnectClockSkewSeconds,
|
||||||
APIBaseURL: updatedSettings.APIBaseURL,
|
OIDCConnectRequireEmailVerified: updatedSettings.OIDCConnectRequireEmailVerified,
|
||||||
ContactInfo: updatedSettings.ContactInfo,
|
OIDCConnectUserInfoEmailPath: updatedSettings.OIDCConnectUserInfoEmailPath,
|
||||||
DocURL: updatedSettings.DocURL,
|
OIDCConnectUserInfoIDPath: updatedSettings.OIDCConnectUserInfoIDPath,
|
||||||
HomeContent: updatedSettings.HomeContent,
|
OIDCConnectUserInfoUsernamePath: updatedSettings.OIDCConnectUserInfoUsernamePath,
|
||||||
HideCcsImportButton: updatedSettings.HideCcsImportButton,
|
SiteName: updatedSettings.SiteName,
|
||||||
PurchaseSubscriptionEnabled: updatedSettings.PurchaseSubscriptionEnabled,
|
SiteLogo: updatedSettings.SiteLogo,
|
||||||
PurchaseSubscriptionURL: updatedSettings.PurchaseSubscriptionURL,
|
SiteSubtitle: updatedSettings.SiteSubtitle,
|
||||||
TableDefaultPageSize: updatedSettings.TableDefaultPageSize,
|
APIBaseURL: updatedSettings.APIBaseURL,
|
||||||
TablePageSizeOptions: updatedSettings.TablePageSizeOptions,
|
ContactInfo: updatedSettings.ContactInfo,
|
||||||
CustomMenuItems: dto.ParseCustomMenuItems(updatedSettings.CustomMenuItems),
|
DocURL: updatedSettings.DocURL,
|
||||||
CustomEndpoints: dto.ParseCustomEndpoints(updatedSettings.CustomEndpoints),
|
HomeContent: updatedSettings.HomeContent,
|
||||||
DefaultConcurrency: updatedSettings.DefaultConcurrency,
|
HideCcsImportButton: updatedSettings.HideCcsImportButton,
|
||||||
DefaultBalance: updatedSettings.DefaultBalance,
|
PurchaseSubscriptionEnabled: updatedSettings.PurchaseSubscriptionEnabled,
|
||||||
DefaultSubscriptions: updatedDefaultSubscriptions,
|
PurchaseSubscriptionURL: updatedSettings.PurchaseSubscriptionURL,
|
||||||
EnableModelFallback: updatedSettings.EnableModelFallback,
|
TableDefaultPageSize: updatedSettings.TableDefaultPageSize,
|
||||||
FallbackModelAnthropic: updatedSettings.FallbackModelAnthropic,
|
TablePageSizeOptions: updatedSettings.TablePageSizeOptions,
|
||||||
FallbackModelOpenAI: updatedSettings.FallbackModelOpenAI,
|
CustomMenuItems: dto.ParseCustomMenuItems(updatedSettings.CustomMenuItems),
|
||||||
FallbackModelGemini: updatedSettings.FallbackModelGemini,
|
CustomEndpoints: dto.ParseCustomEndpoints(updatedSettings.CustomEndpoints),
|
||||||
FallbackModelAntigravity: updatedSettings.FallbackModelAntigravity,
|
DefaultConcurrency: updatedSettings.DefaultConcurrency,
|
||||||
EnableIdentityPatch: updatedSettings.EnableIdentityPatch,
|
DefaultBalance: updatedSettings.DefaultBalance,
|
||||||
IdentityPatchPrompt: updatedSettings.IdentityPatchPrompt,
|
DefaultSubscriptions: updatedDefaultSubscriptions,
|
||||||
OpsMonitoringEnabled: updatedSettings.OpsMonitoringEnabled,
|
EnableModelFallback: updatedSettings.EnableModelFallback,
|
||||||
OpsRealtimeMonitoringEnabled: updatedSettings.OpsRealtimeMonitoringEnabled,
|
FallbackModelAnthropic: updatedSettings.FallbackModelAnthropic,
|
||||||
OpsQueryModeDefault: updatedSettings.OpsQueryModeDefault,
|
FallbackModelOpenAI: updatedSettings.FallbackModelOpenAI,
|
||||||
OpsMetricsIntervalSeconds: updatedSettings.OpsMetricsIntervalSeconds,
|
FallbackModelGemini: updatedSettings.FallbackModelGemini,
|
||||||
MinClaudeCodeVersion: updatedSettings.MinClaudeCodeVersion,
|
FallbackModelAntigravity: updatedSettings.FallbackModelAntigravity,
|
||||||
MaxClaudeCodeVersion: updatedSettings.MaxClaudeCodeVersion,
|
EnableIdentityPatch: updatedSettings.EnableIdentityPatch,
|
||||||
AllowUngroupedKeyScheduling: updatedSettings.AllowUngroupedKeyScheduling,
|
IdentityPatchPrompt: updatedSettings.IdentityPatchPrompt,
|
||||||
BackendModeEnabled: updatedSettings.BackendModeEnabled,
|
OpsMonitoringEnabled: updatedSettings.OpsMonitoringEnabled,
|
||||||
EnableFingerprintUnification: updatedSettings.EnableFingerprintUnification,
|
OpsRealtimeMonitoringEnabled: updatedSettings.OpsRealtimeMonitoringEnabled,
|
||||||
EnableMetadataPassthrough: updatedSettings.EnableMetadataPassthrough,
|
OpsQueryModeDefault: updatedSettings.OpsQueryModeDefault,
|
||||||
EnableCCHSigning: updatedSettings.EnableCCHSigning,
|
OpsMetricsIntervalSeconds: updatedSettings.OpsMetricsIntervalSeconds,
|
||||||
PaymentVisibleMethodAlipaySource: updatedSettings.PaymentVisibleMethodAlipaySource,
|
MinClaudeCodeVersion: updatedSettings.MinClaudeCodeVersion,
|
||||||
PaymentVisibleMethodWxpaySource: updatedSettings.PaymentVisibleMethodWxpaySource,
|
MaxClaudeCodeVersion: updatedSettings.MaxClaudeCodeVersion,
|
||||||
PaymentVisibleMethodAlipayEnabled: updatedSettings.PaymentVisibleMethodAlipayEnabled,
|
AllowUngroupedKeyScheduling: updatedSettings.AllowUngroupedKeyScheduling,
|
||||||
PaymentVisibleMethodWxpayEnabled: updatedSettings.PaymentVisibleMethodWxpayEnabled,
|
BackendModeEnabled: updatedSettings.BackendModeEnabled,
|
||||||
OpenAIAdvancedSchedulerEnabled: updatedSettings.OpenAIAdvancedSchedulerEnabled,
|
EnableFingerprintUnification: updatedSettings.EnableFingerprintUnification,
|
||||||
BalanceLowNotifyEnabled: updatedSettings.BalanceLowNotifyEnabled,
|
EnableMetadataPassthrough: updatedSettings.EnableMetadataPassthrough,
|
||||||
BalanceLowNotifyThreshold: updatedSettings.BalanceLowNotifyThreshold,
|
EnableCCHSigning: updatedSettings.EnableCCHSigning,
|
||||||
BalanceLowNotifyRechargeURL: updatedSettings.BalanceLowNotifyRechargeURL,
|
PaymentVisibleMethodAlipaySource: updatedSettings.PaymentVisibleMethodAlipaySource,
|
||||||
AccountQuotaNotifyEnabled: updatedSettings.AccountQuotaNotifyEnabled,
|
PaymentVisibleMethodWxpaySource: updatedSettings.PaymentVisibleMethodWxpaySource,
|
||||||
AccountQuotaNotifyEmails: dto.NotifyEmailEntriesFromService(updatedSettings.AccountQuotaNotifyEmails),
|
PaymentVisibleMethodAlipayEnabled: updatedSettings.PaymentVisibleMethodAlipayEnabled,
|
||||||
PaymentEnabled: updatedPaymentCfg.Enabled,
|
PaymentVisibleMethodWxpayEnabled: updatedSettings.PaymentVisibleMethodWxpayEnabled,
|
||||||
PaymentMinAmount: updatedPaymentCfg.MinAmount,
|
OpenAIAdvancedSchedulerEnabled: updatedSettings.OpenAIAdvancedSchedulerEnabled,
|
||||||
PaymentMaxAmount: updatedPaymentCfg.MaxAmount,
|
BalanceLowNotifyEnabled: updatedSettings.BalanceLowNotifyEnabled,
|
||||||
PaymentDailyLimit: updatedPaymentCfg.DailyLimit,
|
BalanceLowNotifyThreshold: updatedSettings.BalanceLowNotifyThreshold,
|
||||||
PaymentOrderTimeoutMin: updatedPaymentCfg.OrderTimeoutMin,
|
BalanceLowNotifyRechargeURL: updatedSettings.BalanceLowNotifyRechargeURL,
|
||||||
PaymentMaxPendingOrders: updatedPaymentCfg.MaxPendingOrders,
|
AccountQuotaNotifyEnabled: updatedSettings.AccountQuotaNotifyEnabled,
|
||||||
PaymentEnabledTypes: updatedPaymentCfg.EnabledTypes,
|
AccountQuotaNotifyEmails: dto.NotifyEmailEntriesFromService(updatedSettings.AccountQuotaNotifyEmails),
|
||||||
PaymentBalanceDisabled: updatedPaymentCfg.BalanceDisabled,
|
PaymentEnabled: updatedPaymentCfg.Enabled,
|
||||||
PaymentBalanceRechargeMultiplier: updatedPaymentCfg.BalanceRechargeMultiplier,
|
PaymentMinAmount: updatedPaymentCfg.MinAmount,
|
||||||
PaymentRechargeFeeRate: updatedPaymentCfg.RechargeFeeRate,
|
PaymentMaxAmount: updatedPaymentCfg.MaxAmount,
|
||||||
PaymentLoadBalanceStrat: updatedPaymentCfg.LoadBalanceStrategy,
|
PaymentDailyLimit: updatedPaymentCfg.DailyLimit,
|
||||||
PaymentProductNamePrefix: updatedPaymentCfg.ProductNamePrefix,
|
PaymentOrderTimeoutMin: updatedPaymentCfg.OrderTimeoutMin,
|
||||||
PaymentProductNameSuffix: updatedPaymentCfg.ProductNameSuffix,
|
PaymentMaxPendingOrders: updatedPaymentCfg.MaxPendingOrders,
|
||||||
PaymentHelpImageURL: updatedPaymentCfg.HelpImageURL,
|
PaymentEnabledTypes: updatedPaymentCfg.EnabledTypes,
|
||||||
PaymentHelpText: updatedPaymentCfg.HelpText,
|
PaymentBalanceDisabled: updatedPaymentCfg.BalanceDisabled,
|
||||||
PaymentCancelRateLimitEnabled: updatedPaymentCfg.CancelRateLimitEnabled,
|
PaymentBalanceRechargeMultiplier: updatedPaymentCfg.BalanceRechargeMultiplier,
|
||||||
PaymentCancelRateLimitMax: updatedPaymentCfg.CancelRateLimitMax,
|
PaymentRechargeFeeRate: updatedPaymentCfg.RechargeFeeRate,
|
||||||
PaymentCancelRateLimitWindow: updatedPaymentCfg.CancelRateLimitWindow,
|
PaymentLoadBalanceStrat: updatedPaymentCfg.LoadBalanceStrategy,
|
||||||
PaymentCancelRateLimitUnit: updatedPaymentCfg.CancelRateLimitUnit,
|
PaymentProductNamePrefix: updatedPaymentCfg.ProductNamePrefix,
|
||||||
PaymentCancelRateLimitMode: updatedPaymentCfg.CancelRateLimitMode,
|
PaymentProductNameSuffix: updatedPaymentCfg.ProductNameSuffix,
|
||||||
|
PaymentHelpImageURL: updatedPaymentCfg.HelpImageURL,
|
||||||
|
PaymentHelpText: updatedPaymentCfg.HelpText,
|
||||||
|
PaymentCancelRateLimitEnabled: updatedPaymentCfg.CancelRateLimitEnabled,
|
||||||
|
PaymentCancelRateLimitMax: updatedPaymentCfg.CancelRateLimitMax,
|
||||||
|
PaymentCancelRateLimitWindow: updatedPaymentCfg.CancelRateLimitWindow,
|
||||||
|
PaymentCancelRateLimitUnit: updatedPaymentCfg.CancelRateLimitUnit,
|
||||||
|
PaymentCancelRateLimitMode: updatedPaymentCfg.CancelRateLimitMode,
|
||||||
}
|
}
|
||||||
response.Success(c, systemSettingsResponseData(payload, updatedAuthSourceDefaults))
|
response.Success(c, systemSettingsResponseData(payload, updatedAuthSourceDefaults))
|
||||||
}
|
}
|
||||||
@@ -1442,12 +1531,33 @@ 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.WeChatConnectOpenAppID != after.WeChatConnectOpenAppID {
|
||||||
|
changed = append(changed, "wechat_connect_open_app_id")
|
||||||
|
}
|
||||||
|
if req.WeChatConnectOpenAppSecret != "" {
|
||||||
|
changed = append(changed, "wechat_connect_open_app_secret")
|
||||||
|
}
|
||||||
|
if before.WeChatConnectMPAppID != after.WeChatConnectMPAppID {
|
||||||
|
changed = append(changed, "wechat_connect_mp_app_id")
|
||||||
|
}
|
||||||
|
if req.WeChatConnectMPAppSecret != "" {
|
||||||
|
changed = append(changed, "wechat_connect_mp_app_secret")
|
||||||
|
}
|
||||||
|
if before.WeChatConnectMobileAppID != after.WeChatConnectMobileAppID {
|
||||||
|
changed = append(changed, "wechat_connect_mobile_app_id")
|
||||||
|
}
|
||||||
|
if req.WeChatConnectMobileAppSecret != "" {
|
||||||
|
changed = append(changed, "wechat_connect_mobile_app_secret")
|
||||||
|
}
|
||||||
if before.WeChatConnectOpenEnabled != after.WeChatConnectOpenEnabled {
|
if before.WeChatConnectOpenEnabled != after.WeChatConnectOpenEnabled {
|
||||||
changed = append(changed, "wechat_connect_open_enabled")
|
changed = append(changed, "wechat_connect_open_enabled")
|
||||||
}
|
}
|
||||||
if before.WeChatConnectMPEnabled != after.WeChatConnectMPEnabled {
|
if before.WeChatConnectMPEnabled != after.WeChatConnectMPEnabled {
|
||||||
changed = append(changed, "wechat_connect_mp_enabled")
|
changed = append(changed, "wechat_connect_mp_enabled")
|
||||||
}
|
}
|
||||||
|
if before.WeChatConnectMobileEnabled != after.WeChatConnectMobileEnabled {
|
||||||
|
changed = append(changed, "wechat_connect_mobile_enabled")
|
||||||
|
}
|
||||||
if before.WeChatConnectMode != after.WeChatConnectMode {
|
if before.WeChatConnectMode != after.WeChatConnectMode {
|
||||||
changed = append(changed, "wechat_connect_mode")
|
changed = append(changed, "wechat_connect_mode")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -753,7 +753,13 @@ func (h *AuthHandler) ensureWeChatBindOwnership(
|
|||||||
}
|
}
|
||||||
for _, identity := range identities {
|
for _, identity := range identities {
|
||||||
if identity != nil && identity.UserID != userID {
|
if identity != nil && identity.UserID != userID {
|
||||||
return infraerrors.Conflict("AUTH_IDENTITY_OWNERSHIP_CONFLICT", "auth identity already belongs to another user")
|
activeOwner, lookupErr := findActiveUserByID(ctx, client, identity.UserID)
|
||||||
|
if lookupErr != nil {
|
||||||
|
return lookupErr
|
||||||
|
}
|
||||||
|
if activeOwner != nil {
|
||||||
|
return infraerrors.Conflict("AUTH_IDENTITY_OWNERSHIP_CONFLICT", "auth identity already belongs to another user")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -778,7 +784,13 @@ func (h *AuthHandler) ensureWeChatBindOwnership(
|
|||||||
}
|
}
|
||||||
for _, channel := range channels {
|
for _, channel := range channels {
|
||||||
if channel != nil && channel.Edges.Identity != nil && channel.Edges.Identity.UserID != userID {
|
if channel != nil && channel.Edges.Identity != nil && channel.Edges.Identity.UserID != userID {
|
||||||
return infraerrors.Conflict("AUTH_IDENTITY_CHANNEL_OWNERSHIP_CONFLICT", "auth identity channel already belongs to another user")
|
activeOwner, lookupErr := findActiveUserByID(ctx, client, channel.Edges.Identity.UserID)
|
||||||
|
if lookupErr != nil {
|
||||||
|
return lookupErr
|
||||||
|
}
|
||||||
|
if activeOwner != nil {
|
||||||
|
return infraerrors.Conflict("AUTH_IDENTITY_CHANNEL_OWNERSHIP_CONFLICT", "auth identity channel already belongs to another user")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
@@ -960,8 +972,8 @@ func (h *AuthHandler) getWeChatOAuthConfig(ctx context.Context, rawMode string,
|
|||||||
|
|
||||||
cfg := wechatOAuthConfig{
|
cfg := wechatOAuthConfig{
|
||||||
mode: mode,
|
mode: mode,
|
||||||
appID: strings.TrimSpace(effective.AppID),
|
appID: strings.TrimSpace(effective.AppIDForMode(mode)),
|
||||||
appSecret: strings.TrimSpace(effective.AppSecret),
|
appSecret: strings.TrimSpace(effective.AppSecretForMode(mode)),
|
||||||
redirectURI: firstNonEmpty(strings.TrimSpace(effective.RedirectURL), resolveWeChatOAuthAbsoluteURL(apiBaseURL, c, "/api/v1/auth/oauth/wechat/callback")),
|
redirectURI: firstNonEmpty(strings.TrimSpace(effective.RedirectURL), resolveWeChatOAuthAbsoluteURL(apiBaseURL, c, "/api/v1/auth/oauth/wechat/callback")),
|
||||||
frontendCallback: firstNonEmpty(strings.TrimSpace(effective.FrontendRedirectURL), wechatOAuthDefaultFrontendCB),
|
frontendCallback: firstNonEmpty(strings.TrimSpace(effective.FrontendRedirectURL), wechatOAuthDefaultFrontendCB),
|
||||||
scope: effective.ScopeForMode(mode),
|
scope: effective.ScopeForMode(mode),
|
||||||
|
|||||||
@@ -54,8 +54,15 @@ 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"`
|
||||||
|
WeChatConnectOpenAppID string `json:"wechat_connect_open_app_id"`
|
||||||
|
WeChatConnectOpenAppSecretConfigured bool `json:"wechat_connect_open_app_secret_configured"`
|
||||||
|
WeChatConnectMPAppID string `json:"wechat_connect_mp_app_id"`
|
||||||
|
WeChatConnectMPAppSecretConfigured bool `json:"wechat_connect_mp_app_secret_configured"`
|
||||||
|
WeChatConnectMobileAppID string `json:"wechat_connect_mobile_app_id"`
|
||||||
|
WeChatConnectMobileAppSecretConfigured bool `json:"wechat_connect_mobile_app_secret_configured"`
|
||||||
WeChatConnectOpenEnabled bool `json:"wechat_connect_open_enabled"`
|
WeChatConnectOpenEnabled bool `json:"wechat_connect_open_enabled"`
|
||||||
WeChatConnectMPEnabled bool `json:"wechat_connect_mp_enabled"`
|
WeChatConnectMPEnabled bool `json:"wechat_connect_mp_enabled"`
|
||||||
|
WeChatConnectMobileEnabled bool `json:"wechat_connect_mobile_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"`
|
||||||
@@ -212,6 +219,7 @@ type PublicSettings struct {
|
|||||||
WeChatOAuthEnabled bool `json:"wechat_oauth_enabled"`
|
WeChatOAuthEnabled bool `json:"wechat_oauth_enabled"`
|
||||||
WeChatOAuthOpenEnabled bool `json:"wechat_oauth_open_enabled"`
|
WeChatOAuthOpenEnabled bool `json:"wechat_oauth_open_enabled"`
|
||||||
WeChatOAuthMPEnabled bool `json:"wechat_oauth_mp_enabled"`
|
WeChatOAuthMPEnabled bool `json:"wechat_oauth_mp_enabled"`
|
||||||
|
WeChatOAuthMobileEnabled bool `json:"wechat_oauth_mobile_enabled"`
|
||||||
OIDCOAuthEnabled bool `json:"oidc_oauth_enabled"`
|
OIDCOAuthEnabled bool `json:"oidc_oauth_enabled"`
|
||||||
OIDCOAuthProviderName string `json:"oidc_oauth_provider_name"`
|
OIDCOAuthProviderName string `json:"oidc_oauth_provider_name"`
|
||||||
SoraClientEnabled bool `json:"sora_client_enabled"`
|
SoraClientEnabled bool `json:"sora_client_enabled"`
|
||||||
|
|||||||
@@ -60,6 +60,7 @@ func (h *SettingHandler) GetPublicSettings(c *gin.Context) {
|
|||||||
WeChatOAuthEnabled: settings.WeChatOAuthEnabled,
|
WeChatOAuthEnabled: settings.WeChatOAuthEnabled,
|
||||||
WeChatOAuthOpenEnabled: settings.WeChatOAuthOpenEnabled,
|
WeChatOAuthOpenEnabled: settings.WeChatOAuthOpenEnabled,
|
||||||
WeChatOAuthMPEnabled: settings.WeChatOAuthMPEnabled,
|
WeChatOAuthMPEnabled: settings.WeChatOAuthMPEnabled,
|
||||||
|
WeChatOAuthMobileEnabled: settings.WeChatOAuthMobileEnabled,
|
||||||
OIDCOAuthEnabled: settings.OIDCOAuthEnabled,
|
OIDCOAuthEnabled: settings.OIDCOAuthEnabled,
|
||||||
OIDCOAuthProviderName: settings.OIDCOAuthProviderName,
|
OIDCOAuthProviderName: settings.OIDCOAuthProviderName,
|
||||||
BackendModeEnabled: settings.BackendModeEnabled,
|
BackendModeEnabled: settings.BackendModeEnabled,
|
||||||
|
|||||||
@@ -115,8 +115,15 @@ 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"
|
||||||
|
SettingKeyWeChatConnectOpenAppID = "wechat_connect_open_app_id"
|
||||||
|
SettingKeyWeChatConnectOpenAppSecret = "wechat_connect_open_app_secret"
|
||||||
|
SettingKeyWeChatConnectMPAppID = "wechat_connect_mp_app_id"
|
||||||
|
SettingKeyWeChatConnectMPAppSecret = "wechat_connect_mp_app_secret"
|
||||||
|
SettingKeyWeChatConnectMobileAppID = "wechat_connect_mobile_app_id"
|
||||||
|
SettingKeyWeChatConnectMobileAppSecret = "wechat_connect_mobile_app_secret"
|
||||||
SettingKeyWeChatConnectOpenEnabled = "wechat_connect_open_enabled"
|
SettingKeyWeChatConnectOpenEnabled = "wechat_connect_open_enabled"
|
||||||
SettingKeyWeChatConnectMPEnabled = "wechat_connect_mp_enabled"
|
SettingKeyWeChatConnectMPEnabled = "wechat_connect_mp_enabled"
|
||||||
|
SettingKeyWeChatConnectMobileEnabled = "wechat_connect_mobile_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,13 +519,15 @@ 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.SupportsMode("mp") || strings.TrimSpace(cfg.AppID) == "" || strings.TrimSpace(cfg.AppSecret) == "" {
|
appID := strings.TrimSpace(cfg.AppIDForMode("mp"))
|
||||||
|
appSecret := strings.TrimSpace(cfg.AppSecretForMode("mp"))
|
||||||
|
if err != nil || !cfg.SupportsMode("mp") || appID == "" || 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",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
return strings.TrimSpace(cfg.AppID), strings.TrimSpace(cfg.AppSecret), nil
|
return appID, appSecret, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func classifyCreatePaymentError(req CreateOrderRequest, providerKey string, err error) error {
|
func classifyCreatePaymentError(req CreateOrderRequest, providerKey string, err error) error {
|
||||||
|
|||||||
@@ -181,14 +181,19 @@ func normalizeWeChatConnectModeSetting(raw string) string {
|
|||||||
switch strings.ToLower(strings.TrimSpace(raw)) {
|
switch strings.ToLower(strings.TrimSpace(raw)) {
|
||||||
case "mp":
|
case "mp":
|
||||||
return "mp"
|
return "mp"
|
||||||
|
case "mobile":
|
||||||
|
return "mobile"
|
||||||
default:
|
default:
|
||||||
return "open"
|
return "open"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func defaultWeChatConnectScopeForMode(mode string) string {
|
func defaultWeChatConnectScopeForMode(mode string) string {
|
||||||
if normalizeWeChatConnectModeSetting(mode) == "mp" {
|
switch normalizeWeChatConnectModeSetting(mode) {
|
||||||
|
case "mp":
|
||||||
return "snsapi_userinfo"
|
return "snsapi_userinfo"
|
||||||
|
case "mobile":
|
||||||
|
return ""
|
||||||
}
|
}
|
||||||
return defaultWeChatConnectScopes
|
return defaultWeChatConnectScopes
|
||||||
}
|
}
|
||||||
@@ -204,37 +209,47 @@ func normalizeWeChatConnectScopeSetting(raw, mode string) string {
|
|||||||
default:
|
default:
|
||||||
return defaultWeChatConnectScopeForMode(mode)
|
return defaultWeChatConnectScopeForMode(mode)
|
||||||
}
|
}
|
||||||
|
case "mobile":
|
||||||
|
return ""
|
||||||
default:
|
default:
|
||||||
return defaultWeChatConnectScopes
|
return defaultWeChatConnectScopes
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseWeChatConnectCapabilitySettings(settings map[string]string, enabled bool, mode string) (bool, bool) {
|
func parseWeChatConnectCapabilitySettings(settings map[string]string, enabled bool, mode string) (bool, bool, bool) {
|
||||||
mode = normalizeWeChatConnectModeSetting(mode)
|
mode = normalizeWeChatConnectModeSetting(mode)
|
||||||
rawOpen, hasOpen := settings[SettingKeyWeChatConnectOpenEnabled]
|
rawOpen, hasOpen := settings[SettingKeyWeChatConnectOpenEnabled]
|
||||||
rawMP, hasMP := settings[SettingKeyWeChatConnectMPEnabled]
|
rawMP, hasMP := settings[SettingKeyWeChatConnectMPEnabled]
|
||||||
|
rawMobile, hasMobile := settings[SettingKeyWeChatConnectMobileEnabled]
|
||||||
openConfigured := hasOpen && strings.TrimSpace(rawOpen) != ""
|
openConfigured := hasOpen && strings.TrimSpace(rawOpen) != ""
|
||||||
mpConfigured := hasMP && strings.TrimSpace(rawMP) != ""
|
mpConfigured := hasMP && strings.TrimSpace(rawMP) != ""
|
||||||
|
mobileConfigured := hasMobile && strings.TrimSpace(rawMobile) != ""
|
||||||
|
|
||||||
if openConfigured || mpConfigured {
|
if openConfigured || mpConfigured || mobileConfigured {
|
||||||
openEnabled := strings.TrimSpace(rawOpen) == "true"
|
openEnabled := strings.TrimSpace(rawOpen) == "true"
|
||||||
mpEnabled := strings.TrimSpace(rawMP) == "true"
|
mpEnabled := strings.TrimSpace(rawMP) == "true"
|
||||||
return openEnabled, mpEnabled
|
mobileEnabled := strings.TrimSpace(rawMobile) == "true"
|
||||||
|
return openEnabled, mpEnabled, mobileEnabled
|
||||||
}
|
}
|
||||||
|
|
||||||
if !enabled {
|
if !enabled {
|
||||||
return false, false
|
return false, false, false
|
||||||
}
|
}
|
||||||
if mode == "mp" {
|
if mode == "mp" {
|
||||||
return false, true
|
return false, true, false
|
||||||
}
|
}
|
||||||
return true, false
|
if mode == "mobile" {
|
||||||
|
return false, false, true
|
||||||
|
}
|
||||||
|
return true, false, false
|
||||||
}
|
}
|
||||||
|
|
||||||
func normalizeWeChatConnectStoredMode(openEnabled, mpEnabled bool, mode string) string {
|
func normalizeWeChatConnectStoredMode(openEnabled, mpEnabled, mobileEnabled bool, mode string) string {
|
||||||
switch {
|
switch {
|
||||||
case mpEnabled:
|
case mpEnabled:
|
||||||
return "mp"
|
return "mp"
|
||||||
|
case mobileEnabled:
|
||||||
|
return "mobile"
|
||||||
case openEnabled:
|
case openEnabled:
|
||||||
return "open"
|
return "open"
|
||||||
default:
|
default:
|
||||||
@@ -310,8 +325,15 @@ func (s *SettingService) GetPublicSettings(ctx context.Context) (*PublicSettings
|
|||||||
SettingKeyWeChatConnectEnabled,
|
SettingKeyWeChatConnectEnabled,
|
||||||
SettingKeyWeChatConnectAppID,
|
SettingKeyWeChatConnectAppID,
|
||||||
SettingKeyWeChatConnectAppSecret,
|
SettingKeyWeChatConnectAppSecret,
|
||||||
|
SettingKeyWeChatConnectOpenAppID,
|
||||||
|
SettingKeyWeChatConnectOpenAppSecret,
|
||||||
|
SettingKeyWeChatConnectMPAppID,
|
||||||
|
SettingKeyWeChatConnectMPAppSecret,
|
||||||
|
SettingKeyWeChatConnectMobileAppID,
|
||||||
|
SettingKeyWeChatConnectMobileAppSecret,
|
||||||
SettingKeyWeChatConnectOpenEnabled,
|
SettingKeyWeChatConnectOpenEnabled,
|
||||||
SettingKeyWeChatConnectMPEnabled,
|
SettingKeyWeChatConnectMPEnabled,
|
||||||
|
SettingKeyWeChatConnectMobileEnabled,
|
||||||
SettingKeyWeChatConnectMode,
|
SettingKeyWeChatConnectMode,
|
||||||
SettingKeyWeChatConnectScopes,
|
SettingKeyWeChatConnectScopes,
|
||||||
SettingKeyWeChatConnectRedirectURL,
|
SettingKeyWeChatConnectRedirectURL,
|
||||||
@@ -350,7 +372,7 @@ func (s *SettingService) GetPublicSettings(ctx context.Context) (*PublicSettings
|
|||||||
if oidcProviderName == "" {
|
if oidcProviderName == "" {
|
||||||
oidcProviderName = "OIDC"
|
oidcProviderName = "OIDC"
|
||||||
}
|
}
|
||||||
weChatEnabled, weChatOpenEnabled, weChatMPEnabled := s.weChatOAuthCapabilitiesFromSettings(settings)
|
weChatEnabled, weChatOpenEnabled, weChatMPEnabled, weChatMobileEnabled := s.weChatOAuthCapabilitiesFromSettings(settings)
|
||||||
|
|
||||||
// Password reset requires email verification to be enabled
|
// Password reset requires email verification to be enabled
|
||||||
emailVerifyEnabled := settings[SettingKeyEmailVerifyEnabled] == "true"
|
emailVerifyEnabled := settings[SettingKeyEmailVerifyEnabled] == "true"
|
||||||
@@ -397,6 +419,7 @@ func (s *SettingService) GetPublicSettings(ctx context.Context) (*PublicSettings
|
|||||||
WeChatOAuthEnabled: weChatEnabled,
|
WeChatOAuthEnabled: weChatEnabled,
|
||||||
WeChatOAuthOpenEnabled: weChatOpenEnabled,
|
WeChatOAuthOpenEnabled: weChatOpenEnabled,
|
||||||
WeChatOAuthMPEnabled: weChatMPEnabled,
|
WeChatOAuthMPEnabled: weChatMPEnabled,
|
||||||
|
WeChatOAuthMobileEnabled: weChatMobileEnabled,
|
||||||
BackendModeEnabled: settings[SettingKeyBackendModeEnabled] == "true",
|
BackendModeEnabled: settings[SettingKeyBackendModeEnabled] == "true",
|
||||||
PaymentEnabled: settings[SettingPaymentEnabled] == "true",
|
PaymentEnabled: settings[SettingPaymentEnabled] == "true",
|
||||||
OIDCOAuthEnabled: oidcEnabled,
|
OIDCOAuthEnabled: oidcEnabled,
|
||||||
@@ -456,6 +479,7 @@ func (s *SettingService) GetPublicSettingsForInjection(ctx context.Context) (any
|
|||||||
WeChatOAuthEnabled bool `json:"wechat_oauth_enabled"`
|
WeChatOAuthEnabled bool `json:"wechat_oauth_enabled"`
|
||||||
WeChatOAuthOpenEnabled bool `json:"wechat_oauth_open_enabled"`
|
WeChatOAuthOpenEnabled bool `json:"wechat_oauth_open_enabled"`
|
||||||
WeChatOAuthMPEnabled bool `json:"wechat_oauth_mp_enabled"`
|
WeChatOAuthMPEnabled bool `json:"wechat_oauth_mp_enabled"`
|
||||||
|
WeChatOAuthMobileEnabled bool `json:"wechat_oauth_mobile_enabled"`
|
||||||
BackendModeEnabled bool `json:"backend_mode_enabled"`
|
BackendModeEnabled bool `json:"backend_mode_enabled"`
|
||||||
PaymentEnabled bool `json:"payment_enabled"`
|
PaymentEnabled bool `json:"payment_enabled"`
|
||||||
OIDCOAuthEnabled bool `json:"oidc_oauth_enabled"`
|
OIDCOAuthEnabled bool `json:"oidc_oauth_enabled"`
|
||||||
@@ -493,6 +517,7 @@ func (s *SettingService) GetPublicSettingsForInjection(ctx context.Context) (any
|
|||||||
WeChatOAuthEnabled: settings.WeChatOAuthEnabled,
|
WeChatOAuthEnabled: settings.WeChatOAuthEnabled,
|
||||||
WeChatOAuthOpenEnabled: settings.WeChatOAuthOpenEnabled,
|
WeChatOAuthOpenEnabled: settings.WeChatOAuthOpenEnabled,
|
||||||
WeChatOAuthMPEnabled: settings.WeChatOAuthMPEnabled,
|
WeChatOAuthMPEnabled: settings.WeChatOAuthMPEnabled,
|
||||||
|
WeChatOAuthMobileEnabled: settings.WeChatOAuthMobileEnabled,
|
||||||
BackendModeEnabled: settings.BackendModeEnabled,
|
BackendModeEnabled: settings.BackendModeEnabled,
|
||||||
PaymentEnabled: settings.PaymentEnabled,
|
PaymentEnabled: settings.PaymentEnabled,
|
||||||
OIDCOAuthEnabled: settings.OIDCOAuthEnabled,
|
OIDCOAuthEnabled: settings.OIDCOAuthEnabled,
|
||||||
@@ -512,15 +537,22 @@ 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"
|
enabled := settings[SettingKeyWeChatConnectEnabled] == "true"
|
||||||
mode := normalizeWeChatConnectModeSetting(settings[SettingKeyWeChatConnectMode])
|
mode := normalizeWeChatConnectModeSetting(settings[SettingKeyWeChatConnectMode])
|
||||||
openEnabled, mpEnabled := parseWeChatConnectCapabilitySettings(settings, enabled, mode)
|
openEnabled, mpEnabled, mobileEnabled := parseWeChatConnectCapabilitySettings(settings, enabled, mode)
|
||||||
mode = normalizeWeChatConnectStoredMode(openEnabled, mpEnabled, mode)
|
mode = normalizeWeChatConnectStoredMode(openEnabled, mpEnabled, mobileEnabled, mode)
|
||||||
|
|
||||||
cfg := WeChatConnectOAuthConfig{
|
cfg := WeChatConnectOAuthConfig{
|
||||||
Enabled: enabled,
|
Enabled: enabled,
|
||||||
AppID: strings.TrimSpace(settings[SettingKeyWeChatConnectAppID]),
|
LegacyAppID: strings.TrimSpace(settings[SettingKeyWeChatConnectAppID]),
|
||||||
AppSecret: strings.TrimSpace(settings[SettingKeyWeChatConnectAppSecret]),
|
LegacyAppSecret: strings.TrimSpace(settings[SettingKeyWeChatConnectAppSecret]),
|
||||||
|
OpenAppID: strings.TrimSpace(firstNonEmpty(settings[SettingKeyWeChatConnectOpenAppID], settings[SettingKeyWeChatConnectAppID])),
|
||||||
|
OpenAppSecret: strings.TrimSpace(firstNonEmpty(settings[SettingKeyWeChatConnectOpenAppSecret], settings[SettingKeyWeChatConnectAppSecret])),
|
||||||
|
MPAppID: strings.TrimSpace(firstNonEmpty(settings[SettingKeyWeChatConnectMPAppID], settings[SettingKeyWeChatConnectAppID])),
|
||||||
|
MPAppSecret: strings.TrimSpace(firstNonEmpty(settings[SettingKeyWeChatConnectMPAppSecret], settings[SettingKeyWeChatConnectAppSecret])),
|
||||||
|
MobileAppID: strings.TrimSpace(firstNonEmpty(settings[SettingKeyWeChatConnectMobileAppID], settings[SettingKeyWeChatConnectAppID])),
|
||||||
|
MobileAppSecret: strings.TrimSpace(firstNonEmpty(settings[SettingKeyWeChatConnectMobileAppSecret], settings[SettingKeyWeChatConnectAppSecret])),
|
||||||
OpenEnabled: openEnabled,
|
OpenEnabled: openEnabled,
|
||||||
MPEnabled: mpEnabled,
|
MPEnabled: mpEnabled,
|
||||||
|
MobileEnabled: mobileEnabled,
|
||||||
Mode: mode,
|
Mode: mode,
|
||||||
Scopes: normalizeWeChatConnectScopeSetting(settings[SettingKeyWeChatConnectScopes], mode),
|
Scopes: normalizeWeChatConnectScopeSetting(settings[SettingKeyWeChatConnectScopes], mode),
|
||||||
RedirectURL: strings.TrimSpace(settings[SettingKeyWeChatConnectRedirectURL]),
|
RedirectURL: strings.TrimSpace(settings[SettingKeyWeChatConnectRedirectURL]),
|
||||||
@@ -533,11 +565,29 @@ func (s *SettingService) parseWeChatConnectOAuthConfig(settings map[string]strin
|
|||||||
if !cfg.Enabled || (!cfg.OpenEnabled && !cfg.MPEnabled) {
|
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.OpenEnabled {
|
||||||
return WeChatConnectOAuthConfig{}, infraerrors.InternalServer("OAUTH_CONFIG_INVALID", "wechat oauth app id not configured")
|
if cfg.AppIDForMode("open") == "" {
|
||||||
|
return WeChatConnectOAuthConfig{}, infraerrors.InternalServer("OAUTH_CONFIG_INVALID", "wechat oauth pc app id not configured")
|
||||||
|
}
|
||||||
|
if cfg.AppSecretForMode("open") == "" {
|
||||||
|
return WeChatConnectOAuthConfig{}, infraerrors.InternalServer("OAUTH_CONFIG_INVALID", "wechat oauth pc app secret not configured")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if cfg.AppSecret == "" {
|
if cfg.MPEnabled {
|
||||||
return WeChatConnectOAuthConfig{}, infraerrors.InternalServer("OAUTH_CONFIG_INVALID", "wechat oauth app secret not configured")
|
if cfg.AppIDForMode("mp") == "" {
|
||||||
|
return WeChatConnectOAuthConfig{}, infraerrors.InternalServer("OAUTH_CONFIG_INVALID", "wechat oauth official account app id not configured")
|
||||||
|
}
|
||||||
|
if cfg.AppSecretForMode("mp") == "" {
|
||||||
|
return WeChatConnectOAuthConfig{}, infraerrors.InternalServer("OAUTH_CONFIG_INVALID", "wechat oauth official account app secret not configured")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if cfg.MobileEnabled {
|
||||||
|
if cfg.AppIDForMode("mobile") == "" {
|
||||||
|
return WeChatConnectOAuthConfig{}, infraerrors.InternalServer("OAUTH_CONFIG_INVALID", "wechat oauth mobile app id not configured")
|
||||||
|
}
|
||||||
|
if cfg.AppSecretForMode("mobile") == "" {
|
||||||
|
return WeChatConnectOAuthConfig{}, infraerrors.InternalServer("OAUTH_CONFIG_INVALID", "wechat oauth mobile app secret not configured")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if cfg.RedirectURL == "" {
|
if cfg.RedirectURL == "" {
|
||||||
return WeChatConnectOAuthConfig{}, infraerrors.InternalServer("OAUTH_CONFIG_INVALID", "wechat oauth redirect url not configured")
|
return WeChatConnectOAuthConfig{}, infraerrors.InternalServer("OAUTH_CONFIG_INVALID", "wechat oauth redirect url not configured")
|
||||||
@@ -554,12 +604,34 @@ func (s *SettingService) parseWeChatConnectOAuthConfig(settings map[string]strin
|
|||||||
return cfg, nil
|
return cfg, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *SettingService) weChatOAuthCapabilitiesFromSettings(settings map[string]string) (bool, bool, bool) {
|
func (s *SettingService) weChatOAuthCapabilitiesFromSettings(settings map[string]string) (bool, bool, bool, bool) {
|
||||||
cfg, err := s.parseWeChatConnectOAuthConfig(settings)
|
if settings[SettingKeyWeChatConnectEnabled] != "true" {
|
||||||
if err != nil {
|
return false, false, false, false
|
||||||
return false, false, false
|
|
||||||
}
|
}
|
||||||
return true, cfg.OpenEnabled, cfg.MPEnabled
|
|
||||||
|
mode := normalizeWeChatConnectModeSetting(settings[SettingKeyWeChatConnectMode])
|
||||||
|
openEnabled, mpEnabled, mobileEnabled := parseWeChatConnectCapabilitySettings(settings, true, mode)
|
||||||
|
redirectURL := strings.TrimSpace(settings[SettingKeyWeChatConnectRedirectURL])
|
||||||
|
frontendRedirectURL := strings.TrimSpace(settings[SettingKeyWeChatConnectFrontendRedirectURL])
|
||||||
|
if frontendRedirectURL == "" {
|
||||||
|
frontendRedirectURL = defaultWeChatConnectFrontend
|
||||||
|
}
|
||||||
|
|
||||||
|
legacyAppID := strings.TrimSpace(settings[SettingKeyWeChatConnectAppID])
|
||||||
|
legacyAppSecret := strings.TrimSpace(settings[SettingKeyWeChatConnectAppSecret])
|
||||||
|
openAppID := strings.TrimSpace(firstNonEmpty(settings[SettingKeyWeChatConnectOpenAppID], legacyAppID))
|
||||||
|
openAppSecret := strings.TrimSpace(firstNonEmpty(settings[SettingKeyWeChatConnectOpenAppSecret], legacyAppSecret))
|
||||||
|
mpAppID := strings.TrimSpace(firstNonEmpty(settings[SettingKeyWeChatConnectMPAppID], legacyAppID))
|
||||||
|
mpAppSecret := strings.TrimSpace(firstNonEmpty(settings[SettingKeyWeChatConnectMPAppSecret], legacyAppSecret))
|
||||||
|
mobileAppID := strings.TrimSpace(firstNonEmpty(settings[SettingKeyWeChatConnectMobileAppID], legacyAppID))
|
||||||
|
mobileAppSecret := strings.TrimSpace(firstNonEmpty(settings[SettingKeyWeChatConnectMobileAppSecret], legacyAppSecret))
|
||||||
|
|
||||||
|
webRedirectReady := redirectURL != "" && frontendRedirectURL != ""
|
||||||
|
openReady := openEnabled && webRedirectReady && openAppID != "" && openAppSecret != ""
|
||||||
|
mpReady := mpEnabled && webRedirectReady && mpAppID != "" && mpAppSecret != ""
|
||||||
|
mobileReady := mobileEnabled && mobileAppID != "" && mobileAppSecret != ""
|
||||||
|
|
||||||
|
return openReady || mpReady || mobileReady, openReady, mpReady, mobileReady
|
||||||
}
|
}
|
||||||
|
|
||||||
// filterUserVisibleMenuItems filters out admin-only menu items from a raw JSON
|
// filterUserVisibleMenuItems filters out admin-only menu items from a raw JSON
|
||||||
@@ -744,9 +816,16 @@ 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.WeChatConnectOpenAppID = strings.TrimSpace(firstNonEmpty(settings.WeChatConnectOpenAppID, settings.WeChatConnectAppID))
|
||||||
|
settings.WeChatConnectOpenAppSecret = strings.TrimSpace(firstNonEmpty(settings.WeChatConnectOpenAppSecret, settings.WeChatConnectAppSecret))
|
||||||
|
settings.WeChatConnectMPAppID = strings.TrimSpace(firstNonEmpty(settings.WeChatConnectMPAppID, settings.WeChatConnectAppID))
|
||||||
|
settings.WeChatConnectMPAppSecret = strings.TrimSpace(firstNonEmpty(settings.WeChatConnectMPAppSecret, settings.WeChatConnectAppSecret))
|
||||||
|
settings.WeChatConnectMobileAppID = strings.TrimSpace(firstNonEmpty(settings.WeChatConnectMobileAppID, settings.WeChatConnectAppID))
|
||||||
|
settings.WeChatConnectMobileAppSecret = strings.TrimSpace(firstNonEmpty(settings.WeChatConnectMobileAppSecret, settings.WeChatConnectAppSecret))
|
||||||
settings.WeChatConnectMode = normalizeWeChatConnectStoredMode(
|
settings.WeChatConnectMode = normalizeWeChatConnectStoredMode(
|
||||||
settings.WeChatConnectOpenEnabled,
|
settings.WeChatConnectOpenEnabled,
|
||||||
settings.WeChatConnectMPEnabled,
|
settings.WeChatConnectMPEnabled,
|
||||||
|
settings.WeChatConnectMobileEnabled,
|
||||||
settings.WeChatConnectMode,
|
settings.WeChatConnectMode,
|
||||||
)
|
)
|
||||||
settings.WeChatConnectScopes = normalizeWeChatConnectScopeSetting(settings.WeChatConnectScopes, settings.WeChatConnectMode)
|
settings.WeChatConnectScopes = normalizeWeChatConnectScopeSetting(settings.WeChatConnectScopes, settings.WeChatConnectMode)
|
||||||
@@ -827,8 +906,12 @@ 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[SettingKeyWeChatConnectOpenAppID] = settings.WeChatConnectOpenAppID
|
||||||
|
updates[SettingKeyWeChatConnectMPAppID] = settings.WeChatConnectMPAppID
|
||||||
|
updates[SettingKeyWeChatConnectMobileAppID] = settings.WeChatConnectMobileAppID
|
||||||
updates[SettingKeyWeChatConnectOpenEnabled] = strconv.FormatBool(settings.WeChatConnectOpenEnabled)
|
updates[SettingKeyWeChatConnectOpenEnabled] = strconv.FormatBool(settings.WeChatConnectOpenEnabled)
|
||||||
updates[SettingKeyWeChatConnectMPEnabled] = strconv.FormatBool(settings.WeChatConnectMPEnabled)
|
updates[SettingKeyWeChatConnectMPEnabled] = strconv.FormatBool(settings.WeChatConnectMPEnabled)
|
||||||
|
updates[SettingKeyWeChatConnectMobileEnabled] = strconv.FormatBool(settings.WeChatConnectMobileEnabled)
|
||||||
updates[SettingKeyWeChatConnectMode] = settings.WeChatConnectMode
|
updates[SettingKeyWeChatConnectMode] = settings.WeChatConnectMode
|
||||||
updates[SettingKeyWeChatConnectScopes] = settings.WeChatConnectScopes
|
updates[SettingKeyWeChatConnectScopes] = settings.WeChatConnectScopes
|
||||||
updates[SettingKeyWeChatConnectRedirectURL] = settings.WeChatConnectRedirectURL
|
updates[SettingKeyWeChatConnectRedirectURL] = settings.WeChatConnectRedirectURL
|
||||||
@@ -836,6 +919,15 @@ func (s *SettingService) buildSystemSettingsUpdates(ctx context.Context, setting
|
|||||||
if settings.WeChatConnectAppSecret != "" {
|
if settings.WeChatConnectAppSecret != "" {
|
||||||
updates[SettingKeyWeChatConnectAppSecret] = settings.WeChatConnectAppSecret
|
updates[SettingKeyWeChatConnectAppSecret] = settings.WeChatConnectAppSecret
|
||||||
}
|
}
|
||||||
|
if settings.WeChatConnectOpenAppSecret != "" {
|
||||||
|
updates[SettingKeyWeChatConnectOpenAppSecret] = settings.WeChatConnectOpenAppSecret
|
||||||
|
}
|
||||||
|
if settings.WeChatConnectMPAppSecret != "" {
|
||||||
|
updates[SettingKeyWeChatConnectMPAppSecret] = settings.WeChatConnectMPAppSecret
|
||||||
|
}
|
||||||
|
if settings.WeChatConnectMobileAppSecret != "" {
|
||||||
|
updates[SettingKeyWeChatConnectMobileAppSecret] = settings.WeChatConnectMobileAppSecret
|
||||||
|
}
|
||||||
|
|
||||||
// OEM设置
|
// OEM设置
|
||||||
updates[SettingKeySiteName] = settings.SiteName
|
updates[SettingKeySiteName] = settings.SiteName
|
||||||
@@ -1344,8 +1436,15 @@ func (s *SettingService) InitializeDefaultSettings(ctx context.Context) error {
|
|||||||
SettingKeyCustomMenuItems: "[]",
|
SettingKeyCustomMenuItems: "[]",
|
||||||
SettingKeyCustomEndpoints: "[]",
|
SettingKeyCustomEndpoints: "[]",
|
||||||
SettingKeyWeChatConnectEnabled: "false",
|
SettingKeyWeChatConnectEnabled: "false",
|
||||||
|
SettingKeyWeChatConnectOpenAppID: "",
|
||||||
|
SettingKeyWeChatConnectOpenAppSecret: "",
|
||||||
|
SettingKeyWeChatConnectMPAppID: "",
|
||||||
|
SettingKeyWeChatConnectMPAppSecret: "",
|
||||||
|
SettingKeyWeChatConnectMobileAppID: "",
|
||||||
|
SettingKeyWeChatConnectMobileAppSecret: "",
|
||||||
SettingKeyWeChatConnectOpenEnabled: "false",
|
SettingKeyWeChatConnectOpenEnabled: "false",
|
||||||
SettingKeyWeChatConnectMPEnabled: "false",
|
SettingKeyWeChatConnectMPEnabled: "false",
|
||||||
|
SettingKeyWeChatConnectMobileEnabled: "false",
|
||||||
SettingKeyWeChatConnectMode: "open",
|
SettingKeyWeChatConnectMode: "open",
|
||||||
SettingKeyWeChatConnectScopes: "snsapi_login",
|
SettingKeyWeChatConnectScopes: "snsapi_login",
|
||||||
SettingKeyWeChatConnectFrontendRedirectURL: defaultWeChatConnectFrontend,
|
SettingKeyWeChatConnectFrontendRedirectURL: defaultWeChatConnectFrontend,
|
||||||
@@ -1645,7 +1744,16 @@ 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.WeChatConnectOpenEnabled, result.WeChatConnectMPEnabled = parseWeChatConnectCapabilitySettings(
|
result.WeChatConnectOpenAppID = strings.TrimSpace(firstNonEmpty(settings[SettingKeyWeChatConnectOpenAppID], result.WeChatConnectAppID))
|
||||||
|
result.WeChatConnectOpenAppSecret = strings.TrimSpace(firstNonEmpty(settings[SettingKeyWeChatConnectOpenAppSecret], result.WeChatConnectAppSecret))
|
||||||
|
result.WeChatConnectOpenAppSecretConfigured = result.WeChatConnectOpenAppSecret != ""
|
||||||
|
result.WeChatConnectMPAppID = strings.TrimSpace(firstNonEmpty(settings[SettingKeyWeChatConnectMPAppID], result.WeChatConnectAppID))
|
||||||
|
result.WeChatConnectMPAppSecret = strings.TrimSpace(firstNonEmpty(settings[SettingKeyWeChatConnectMPAppSecret], result.WeChatConnectAppSecret))
|
||||||
|
result.WeChatConnectMPAppSecretConfigured = result.WeChatConnectMPAppSecret != ""
|
||||||
|
result.WeChatConnectMobileAppID = strings.TrimSpace(firstNonEmpty(settings[SettingKeyWeChatConnectMobileAppID], result.WeChatConnectAppID))
|
||||||
|
result.WeChatConnectMobileAppSecret = strings.TrimSpace(firstNonEmpty(settings[SettingKeyWeChatConnectMobileAppSecret], result.WeChatConnectAppSecret))
|
||||||
|
result.WeChatConnectMobileAppSecretConfigured = result.WeChatConnectMobileAppSecret != ""
|
||||||
|
result.WeChatConnectOpenEnabled, result.WeChatConnectMPEnabled, result.WeChatConnectMobileEnabled = parseWeChatConnectCapabilitySettings(
|
||||||
settings,
|
settings,
|
||||||
result.WeChatConnectEnabled,
|
result.WeChatConnectEnabled,
|
||||||
settings[SettingKeyWeChatConnectMode],
|
settings[SettingKeyWeChatConnectMode],
|
||||||
@@ -1653,6 +1761,7 @@ func (s *SettingService) parseSettings(settings map[string]string) *SystemSettin
|
|||||||
result.WeChatConnectMode = normalizeWeChatConnectStoredMode(
|
result.WeChatConnectMode = normalizeWeChatConnectStoredMode(
|
||||||
result.WeChatConnectOpenEnabled,
|
result.WeChatConnectOpenEnabled,
|
||||||
result.WeChatConnectMPEnabled,
|
result.WeChatConnectMPEnabled,
|
||||||
|
result.WeChatConnectMobileEnabled,
|
||||||
settings[SettingKeyWeChatConnectMode],
|
settings[SettingKeyWeChatConnectMode],
|
||||||
)
|
)
|
||||||
result.WeChatConnectScopes = normalizeWeChatConnectScopeSetting(settings[SettingKeyWeChatConnectScopes], result.WeChatConnectMode)
|
result.WeChatConnectScopes = normalizeWeChatConnectScopeSetting(settings[SettingKeyWeChatConnectScopes], result.WeChatConnectMode)
|
||||||
@@ -2151,8 +2260,15 @@ func (s *SettingService) GetWeChatConnectOAuthConfig(ctx context.Context) (WeCha
|
|||||||
SettingKeyWeChatConnectEnabled,
|
SettingKeyWeChatConnectEnabled,
|
||||||
SettingKeyWeChatConnectAppID,
|
SettingKeyWeChatConnectAppID,
|
||||||
SettingKeyWeChatConnectAppSecret,
|
SettingKeyWeChatConnectAppSecret,
|
||||||
|
SettingKeyWeChatConnectOpenAppID,
|
||||||
|
SettingKeyWeChatConnectOpenAppSecret,
|
||||||
|
SettingKeyWeChatConnectMPAppID,
|
||||||
|
SettingKeyWeChatConnectMPAppSecret,
|
||||||
|
SettingKeyWeChatConnectMobileAppID,
|
||||||
|
SettingKeyWeChatConnectMobileAppSecret,
|
||||||
SettingKeyWeChatConnectOpenEnabled,
|
SettingKeyWeChatConnectOpenEnabled,
|
||||||
SettingKeyWeChatConnectMPEnabled,
|
SettingKeyWeChatConnectMPEnabled,
|
||||||
|
SettingKeyWeChatConnectMobileEnabled,
|
||||||
SettingKeyWeChatConnectMode,
|
SettingKeyWeChatConnectMode,
|
||||||
SettingKeyWeChatConnectScopes,
|
SettingKeyWeChatConnectScopes,
|
||||||
SettingKeyWeChatConnectRedirectURL,
|
SettingKeyWeChatConnectRedirectURL,
|
||||||
|
|||||||
@@ -1,5 +1,16 @@
|
|||||||
package service
|
package service
|
||||||
|
|
||||||
|
import "strings"
|
||||||
|
|
||||||
|
func firstNonEmpty(values ...string) string {
|
||||||
|
for _, value := range values {
|
||||||
|
if trimmed := strings.TrimSpace(value); trimmed != "" {
|
||||||
|
return trimmed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
type SystemSettings struct {
|
type SystemSettings struct {
|
||||||
RegistrationEnabled bool
|
RegistrationEnabled bool
|
||||||
EmailVerifyEnabled bool
|
EmailVerifyEnabled bool
|
||||||
@@ -32,16 +43,26 @@ type SystemSettings struct {
|
|||||||
LinuxDoConnectRedirectURL string
|
LinuxDoConnectRedirectURL string
|
||||||
|
|
||||||
// WeChat Connect OAuth 登录
|
// WeChat Connect OAuth 登录
|
||||||
WeChatConnectEnabled bool
|
WeChatConnectEnabled bool
|
||||||
WeChatConnectAppID string
|
WeChatConnectAppID string
|
||||||
WeChatConnectAppSecret string
|
WeChatConnectAppSecret string
|
||||||
WeChatConnectAppSecretConfigured bool
|
WeChatConnectAppSecretConfigured bool
|
||||||
WeChatConnectOpenEnabled bool
|
WeChatConnectOpenAppID string
|
||||||
WeChatConnectMPEnabled bool
|
WeChatConnectOpenAppSecret string
|
||||||
WeChatConnectMode string
|
WeChatConnectOpenAppSecretConfigured bool
|
||||||
WeChatConnectScopes string
|
WeChatConnectMPAppID string
|
||||||
WeChatConnectRedirectURL string
|
WeChatConnectMPAppSecret string
|
||||||
WeChatConnectFrontendRedirectURL string
|
WeChatConnectMPAppSecretConfigured bool
|
||||||
|
WeChatConnectMobileAppID string
|
||||||
|
WeChatConnectMobileAppSecret string
|
||||||
|
WeChatConnectMobileAppSecretConfigured bool
|
||||||
|
WeChatConnectOpenEnabled bool
|
||||||
|
WeChatConnectMPEnabled bool
|
||||||
|
WeChatConnectMobileEnabled bool
|
||||||
|
WeChatConnectMode string
|
||||||
|
WeChatConnectScopes string
|
||||||
|
WeChatConnectRedirectURL string
|
||||||
|
WeChatConnectFrontendRedirectURL string
|
||||||
|
|
||||||
// Generic OIDC OAuth 登录
|
// Generic OIDC OAuth 登录
|
||||||
OIDCConnectEnabled bool
|
OIDCConnectEnabled bool
|
||||||
@@ -173,15 +194,16 @@ type PublicSettings struct {
|
|||||||
CustomMenuItems string // JSON array of custom menu items
|
CustomMenuItems string // JSON array of custom menu items
|
||||||
CustomEndpoints string // JSON array of custom endpoints
|
CustomEndpoints string // JSON array of custom endpoints
|
||||||
|
|
||||||
LinuxDoOAuthEnabled bool
|
LinuxDoOAuthEnabled bool
|
||||||
WeChatOAuthEnabled bool
|
WeChatOAuthEnabled bool
|
||||||
WeChatOAuthOpenEnabled bool
|
WeChatOAuthOpenEnabled bool
|
||||||
WeChatOAuthMPEnabled bool
|
WeChatOAuthMPEnabled bool
|
||||||
BackendModeEnabled bool
|
WeChatOAuthMobileEnabled bool
|
||||||
PaymentEnabled bool
|
BackendModeEnabled bool
|
||||||
OIDCOAuthEnabled bool
|
PaymentEnabled bool
|
||||||
OIDCOAuthProviderName string
|
OIDCOAuthEnabled bool
|
||||||
Version string
|
OIDCOAuthProviderName string
|
||||||
|
Version string
|
||||||
|
|
||||||
BalanceLowNotifyEnabled bool
|
BalanceLowNotifyEnabled bool
|
||||||
AccountQuotaNotifyEnabled bool
|
AccountQuotaNotifyEnabled bool
|
||||||
@@ -191,10 +213,17 @@ type PublicSettings struct {
|
|||||||
|
|
||||||
type WeChatConnectOAuthConfig struct {
|
type WeChatConnectOAuthConfig struct {
|
||||||
Enabled bool
|
Enabled bool
|
||||||
AppID string
|
LegacyAppID string
|
||||||
AppSecret string
|
LegacyAppSecret string
|
||||||
|
OpenAppID string
|
||||||
|
OpenAppSecret string
|
||||||
|
MPAppID string
|
||||||
|
MPAppSecret string
|
||||||
|
MobileAppID string
|
||||||
|
MobileAppSecret string
|
||||||
OpenEnabled bool
|
OpenEnabled bool
|
||||||
MPEnabled bool
|
MPEnabled bool
|
||||||
|
MobileEnabled bool
|
||||||
Mode string
|
Mode string
|
||||||
Scopes string
|
Scopes string
|
||||||
RedirectURL string
|
RedirectURL string
|
||||||
@@ -205,18 +234,43 @@ func (cfg WeChatConnectOAuthConfig) SupportsMode(mode string) bool {
|
|||||||
switch normalizeWeChatConnectModeSetting(mode) {
|
switch normalizeWeChatConnectModeSetting(mode) {
|
||||||
case "mp":
|
case "mp":
|
||||||
return cfg.MPEnabled
|
return cfg.MPEnabled
|
||||||
|
case "mobile":
|
||||||
|
return cfg.MobileEnabled
|
||||||
default:
|
default:
|
||||||
return cfg.OpenEnabled
|
return cfg.OpenEnabled
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cfg WeChatConnectOAuthConfig) ScopeForMode(mode string) string {
|
func (cfg WeChatConnectOAuthConfig) ScopeForMode(mode string) string {
|
||||||
if normalizeWeChatConnectModeSetting(mode) == "mp" {
|
switch normalizeWeChatConnectModeSetting(mode) {
|
||||||
|
case "mp":
|
||||||
return normalizeWeChatConnectScopeSetting(cfg.Scopes, "mp")
|
return normalizeWeChatConnectScopeSetting(cfg.Scopes, "mp")
|
||||||
|
case "mobile":
|
||||||
|
return ""
|
||||||
}
|
}
|
||||||
return defaultWeChatConnectScopeForMode("open")
|
return defaultWeChatConnectScopeForMode("open")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (cfg WeChatConnectOAuthConfig) AppIDForMode(mode string) string {
|
||||||
|
switch normalizeWeChatConnectModeSetting(mode) {
|
||||||
|
case "mp":
|
||||||
|
return strings.TrimSpace(firstNonEmpty(cfg.MPAppID, cfg.LegacyAppID))
|
||||||
|
case "mobile":
|
||||||
|
return strings.TrimSpace(firstNonEmpty(cfg.MobileAppID, cfg.LegacyAppID))
|
||||||
|
}
|
||||||
|
return strings.TrimSpace(firstNonEmpty(cfg.OpenAppID, cfg.LegacyAppID))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cfg WeChatConnectOAuthConfig) AppSecretForMode(mode string) string {
|
||||||
|
switch normalizeWeChatConnectModeSetting(mode) {
|
||||||
|
case "mp":
|
||||||
|
return strings.TrimSpace(firstNonEmpty(cfg.MPAppSecret, cfg.LegacyAppSecret))
|
||||||
|
case "mobile":
|
||||||
|
return strings.TrimSpace(firstNonEmpty(cfg.MobileAppSecret, cfg.LegacyAppSecret))
|
||||||
|
}
|
||||||
|
return strings.TrimSpace(firstNonEmpty(cfg.OpenAppSecret, cfg.LegacyAppSecret))
|
||||||
|
}
|
||||||
|
|
||||||
// StreamTimeoutSettings 流超时处理配置(仅控制超时后的处理方式,超时判定由网关配置控制)
|
// StreamTimeoutSettings 流超时处理配置(仅控制超时后的处理方式,超时判定由网关配置控制)
|
||||||
type StreamTimeoutSettings struct {
|
type StreamTimeoutSettings struct {
|
||||||
// Enabled 是否启用流超时处理
|
// Enabled 是否启用流超时处理
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ export type PaymentVisibleMethodSource =
|
|||||||
| "easypay_alipay"
|
| "easypay_alipay"
|
||||||
| "official_wxpay"
|
| "official_wxpay"
|
||||||
| "easypay_wxpay";
|
| "easypay_wxpay";
|
||||||
export type WeChatConnectMode = "open" | "mp";
|
export type WeChatConnectMode = "open" | "mp" | "mobile";
|
||||||
|
|
||||||
export interface PaymentVisibleMethodSourceOption {
|
export interface PaymentVisibleMethodSourceOption {
|
||||||
value: PaymentVisibleMethodSource;
|
value: PaymentVisibleMethodSource;
|
||||||
@@ -108,11 +108,16 @@ const PAYMENT_VISIBLE_METHOD_SOURCE_ALIASES: Record<
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
const WECHAT_CONNECT_MODE_OPTIONS: WeChatConnectModeOption[] = [
|
const WECHAT_CONNECT_MODE_OPTIONS: WeChatConnectModeOption[] = [
|
||||||
{ value: "open", labelZh: "微信开放平台", labelEn: "WeChat Open Platform" },
|
{ value: "open", labelZh: "PC 应用", labelEn: "PC App" },
|
||||||
{
|
{
|
||||||
value: "mp",
|
value: "mp",
|
||||||
labelZh: "微信公众号 / 小程序",
|
labelZh: "公众号",
|
||||||
labelEn: "WeChat Official Account / Mini Program",
|
labelEn: "Official Account",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: "mobile",
|
||||||
|
labelZh: "移动应用",
|
||||||
|
labelEn: "Mobile App",
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
const WECHAT_CONNECT_MODE_ALIASES: Record<string, WeChatConnectMode> = {
|
const WECHAT_CONNECT_MODE_ALIASES: Record<string, WeChatConnectMode> = {
|
||||||
@@ -124,6 +129,9 @@ const WECHAT_CONNECT_MODE_ALIASES: Record<string, WeChatConnectMode> = {
|
|||||||
official_account: "mp",
|
official_account: "mp",
|
||||||
wechat_mp: "mp",
|
wechat_mp: "mp",
|
||||||
mini_program: "mp",
|
mini_program: "mp",
|
||||||
|
mobile: "mobile",
|
||||||
|
mobile_app: "mobile",
|
||||||
|
native_app: "mobile",
|
||||||
};
|
};
|
||||||
|
|
||||||
export function normalizeDefaultSubscriptionSettings(
|
export function normalizeDefaultSubscriptionSettings(
|
||||||
@@ -234,34 +242,52 @@ export function normalizeWeChatConnectMode(source: unknown): WeChatConnectMode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function defaultWeChatConnectScopesForMode(mode: unknown): string {
|
export function defaultWeChatConnectScopesForMode(mode: unknown): string {
|
||||||
return normalizeWeChatConnectMode(mode) === "mp"
|
switch (normalizeWeChatConnectMode(mode)) {
|
||||||
? "snsapi_userinfo"
|
case "mp":
|
||||||
: "snsapi_login";
|
return "snsapi_userinfo";
|
||||||
|
case "mobile":
|
||||||
|
return "";
|
||||||
|
default:
|
||||||
|
return "snsapi_login";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function resolveWeChatConnectModeCapabilities(
|
export function resolveWeChatConnectModeCapabilities(
|
||||||
openEnabled: unknown,
|
openEnabled: unknown,
|
||||||
mpEnabled: unknown,
|
mpEnabled: unknown,
|
||||||
|
mobileEnabled: unknown,
|
||||||
legacyMode: unknown,
|
legacyMode: unknown,
|
||||||
): { openEnabled: boolean; mpEnabled: boolean } {
|
): { openEnabled: boolean; mpEnabled: boolean; mobileEnabled: boolean } {
|
||||||
if (typeof openEnabled === "boolean" || typeof mpEnabled === "boolean") {
|
if (
|
||||||
|
typeof openEnabled === "boolean" ||
|
||||||
|
typeof mpEnabled === "boolean" ||
|
||||||
|
typeof mobileEnabled === "boolean"
|
||||||
|
) {
|
||||||
return {
|
return {
|
||||||
openEnabled: openEnabled === true,
|
openEnabled: openEnabled === true,
|
||||||
mpEnabled: mpEnabled === true,
|
mpEnabled: mpEnabled === true,
|
||||||
|
mobileEnabled: mobileEnabled === true,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
return normalizeWeChatConnectMode(legacyMode) === "mp"
|
switch (normalizeWeChatConnectMode(legacyMode)) {
|
||||||
? { openEnabled: false, mpEnabled: true }
|
case "mp":
|
||||||
: { openEnabled: true, mpEnabled: false };
|
return { openEnabled: false, mpEnabled: true, mobileEnabled: false };
|
||||||
|
case "mobile":
|
||||||
|
return { openEnabled: false, mpEnabled: false, mobileEnabled: true };
|
||||||
|
default:
|
||||||
|
return { openEnabled: true, mpEnabled: false, mobileEnabled: false };
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function deriveWeChatConnectStoredMode(
|
export function deriveWeChatConnectStoredMode(
|
||||||
openEnabled: boolean,
|
openEnabled: boolean,
|
||||||
mpEnabled: boolean,
|
mpEnabled: boolean,
|
||||||
|
mobileEnabled: boolean,
|
||||||
legacyMode: unknown,
|
legacyMode: unknown,
|
||||||
): WeChatConnectMode {
|
): WeChatConnectMode {
|
||||||
if (mpEnabled) return "mp";
|
if (mpEnabled) return "mp";
|
||||||
|
if (mobileEnabled) return "mobile";
|
||||||
if (openEnabled) return "open";
|
if (openEnabled) return "open";
|
||||||
return normalizeWeChatConnectMode(legacyMode);
|
return normalizeWeChatConnectMode(legacyMode);
|
||||||
}
|
}
|
||||||
@@ -342,8 +368,15 @@ 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_app_id?: string;
|
||||||
|
wechat_connect_open_app_secret_configured?: boolean;
|
||||||
|
wechat_connect_mp_app_id?: string;
|
||||||
|
wechat_connect_mp_app_secret_configured?: boolean;
|
||||||
|
wechat_connect_mobile_app_id?: string;
|
||||||
|
wechat_connect_mobile_app_secret_configured?: boolean;
|
||||||
wechat_connect_open_enabled?: boolean;
|
wechat_connect_open_enabled?: boolean;
|
||||||
wechat_connect_mp_enabled?: boolean;
|
wechat_connect_mp_enabled?: boolean;
|
||||||
|
wechat_connect_mobile_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;
|
||||||
@@ -501,8 +534,15 @@ 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_app_id?: string;
|
||||||
|
wechat_connect_open_app_secret?: string;
|
||||||
|
wechat_connect_mp_app_id?: string;
|
||||||
|
wechat_connect_mp_app_secret?: string;
|
||||||
|
wechat_connect_mobile_app_id?: string;
|
||||||
|
wechat_connect_mobile_app_secret?: string;
|
||||||
wechat_connect_open_enabled?: boolean;
|
wechat_connect_open_enabled?: boolean;
|
||||||
wechat_connect_mp_enabled?: boolean;
|
wechat_connect_mp_enabled?: boolean;
|
||||||
|
wechat_connect_mobile_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;
|
||||||
|
|||||||
@@ -57,6 +57,11 @@ const disabledHint = computed(() => {
|
|||||||
return t('auth.oauthFlow.wechatSystemBrowserOnly')
|
return t('auth.oauthFlow.wechatSystemBrowserOnly')
|
||||||
case 'wechat_browser_required':
|
case 'wechat_browser_required':
|
||||||
return t('auth.oauthFlow.wechatBrowserOnly')
|
return t('auth.oauthFlow.wechatBrowserOnly')
|
||||||
|
case 'native_app_required':
|
||||||
|
return localizeWeChatHint(
|
||||||
|
'当前仅配置微信移动应用登录,需要在原生 App 中通过微信 SDK 发起授权。',
|
||||||
|
'This site only has WeChat mobile app login configured. Continue from the native app through the WeChat SDK.',
|
||||||
|
)
|
||||||
case 'not_configured':
|
case 'not_configured':
|
||||||
return t('auth.oauthFlow.wechatNotConfigured')
|
return t('auth.oauthFlow.wechatNotConfigured')
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -344,6 +344,7 @@ export const useAppStore = defineStore('app', () => {
|
|||||||
wechat_oauth_enabled: false,
|
wechat_oauth_enabled: false,
|
||||||
wechat_oauth_open_enabled: false,
|
wechat_oauth_open_enabled: false,
|
||||||
wechat_oauth_mp_enabled: false,
|
wechat_oauth_mp_enabled: false,
|
||||||
|
wechat_oauth_mobile_enabled: false,
|
||||||
oidc_oauth_enabled: false,
|
oidc_oauth_enabled: false,
|
||||||
oidc_oauth_provider_name: 'OIDC',
|
oidc_oauth_provider_name: 'OIDC',
|
||||||
backend_mode_enabled: false,
|
backend_mode_enabled: false,
|
||||||
|
|||||||
@@ -168,6 +168,7 @@ export interface PublicSettings {
|
|||||||
wechat_oauth_enabled: boolean
|
wechat_oauth_enabled: boolean
|
||||||
wechat_oauth_open_enabled?: boolean
|
wechat_oauth_open_enabled?: boolean
|
||||||
wechat_oauth_mp_enabled?: boolean
|
wechat_oauth_mp_enabled?: boolean
|
||||||
|
wechat_oauth_mobile_enabled?: boolean
|
||||||
oidc_oauth_enabled: boolean
|
oidc_oauth_enabled: boolean
|
||||||
oidc_oauth_provider_name: string
|
oidc_oauth_provider_name: string
|
||||||
backend_mode_enabled: boolean
|
backend_mode_enabled: boolean
|
||||||
|
|||||||
@@ -1398,101 +1398,253 @@
|
|||||||
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-2">
|
<div class="space-y-4">
|
||||||
<div>
|
<div
|
||||||
<label
|
class="rounded-lg border border-gray-200 p-4 dark:border-dark-700"
|
||||||
class="mb-2 block text-sm font-medium text-gray-700 dark:text-gray-300"
|
>
|
||||||
|
<div class="flex items-start justify-between gap-4">
|
||||||
|
<div>
|
||||||
|
<h3 class="font-medium text-gray-900 dark:text-white">
|
||||||
|
{{ localText("PC 应用", "PC App") }}
|
||||||
|
</h3>
|
||||||
|
<p class="mt-1 text-sm text-gray-500 dark:text-gray-400">
|
||||||
|
{{
|
||||||
|
localText(
|
||||||
|
"桌面浏览器通过微信开放平台扫码登录。可与公众号或移动应用同时存在。",
|
||||||
|
"Desktop browsers sign in through WeChat Open Platform QR login. This can coexist with Official Account or Mobile App.",
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<Toggle
|
||||||
|
:model-value="form.wechat_connect_open_enabled"
|
||||||
|
data-testid="wechat-connect-open-enabled"
|
||||||
|
@update:model-value="handleWeChatOpenEnabledChange"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
v-if="form.wechat_connect_open_enabled"
|
||||||
|
class="mt-4 grid grid-cols-1 gap-4 lg:grid-cols-2"
|
||||||
>
|
>
|
||||||
{{ t("admin.settings.wechatConnect.appIdLabel") }}
|
<div>
|
||||||
</label>
|
<label
|
||||||
<input
|
class="mb-2 block text-sm font-medium text-gray-700 dark:text-gray-300"
|
||||||
data-testid="wechat-connect-app-id"
|
>
|
||||||
v-model="form.wechat_connect_app_id"
|
{{ localText("PC AppID", "PC App ID") }}
|
||||||
type="text"
|
</label>
|
||||||
class="input font-mono text-sm"
|
<input
|
||||||
:placeholder="t('admin.settings.wechatConnect.appIdPlaceholder')"
|
v-model="form.wechat_connect_open_app_id"
|
||||||
/>
|
type="text"
|
||||||
|
class="input font-mono text-sm"
|
||||||
|
:placeholder="
|
||||||
|
localText(
|
||||||
|
'微信开放平台 PC 应用 AppID',
|
||||||
|
'WeChat Open Platform PC App ID',
|
||||||
|
)
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label
|
||||||
|
class="mb-2 block text-sm font-medium text-gray-700 dark:text-gray-300"
|
||||||
|
>
|
||||||
|
{{ localText("PC AppSecret", "PC App Secret") }}
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
v-model="form.wechat_connect_open_app_secret"
|
||||||
|
type="password"
|
||||||
|
class="input font-mono text-sm"
|
||||||
|
:placeholder="
|
||||||
|
form.wechat_connect_open_app_secret_configured
|
||||||
|
? localText(
|
||||||
|
'密钥已配置,留空以保留当前值。',
|
||||||
|
'Secret configured. Leave empty to keep the current value.',
|
||||||
|
)
|
||||||
|
: localText(
|
||||||
|
'微信开放平台 PC 应用 AppSecret',
|
||||||
|
'WeChat Open Platform PC App Secret',
|
||||||
|
)
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div
|
||||||
<label
|
class="rounded-lg border border-gray-200 p-4 dark:border-dark-700"
|
||||||
class="mb-2 block text-sm font-medium text-gray-700 dark:text-gray-300"
|
>
|
||||||
|
<div class="flex items-start justify-between gap-4">
|
||||||
|
<div>
|
||||||
|
<h3 class="font-medium text-gray-900 dark:text-white">
|
||||||
|
{{ localText("公众号", "Official Account") }}
|
||||||
|
</h3>
|
||||||
|
<p class="mt-1 text-sm text-gray-500 dark:text-gray-400">
|
||||||
|
{{
|
||||||
|
localText(
|
||||||
|
"仅在微信内浏览器可用;非微信环境下会显示不可用。",
|
||||||
|
"Only available inside the WeChat browser. It is shown as unavailable outside WeChat.",
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<Toggle
|
||||||
|
:model-value="form.wechat_connect_mp_enabled"
|
||||||
|
data-testid="wechat-connect-mp-enabled"
|
||||||
|
@update:model-value="handleWeChatMPEnabledChange"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
v-if="form.wechat_connect_mp_enabled"
|
||||||
|
class="mt-4 grid grid-cols-1 gap-4 lg:grid-cols-2"
|
||||||
>
|
>
|
||||||
{{ t("admin.settings.wechatConnect.appSecretLabel") }}
|
<div>
|
||||||
</label>
|
<label
|
||||||
<input
|
class="mb-2 block text-sm font-medium text-gray-700 dark:text-gray-300"
|
||||||
data-testid="wechat-connect-app-secret"
|
>
|
||||||
v-model="form.wechat_connect_app_secret"
|
{{ localText("公众号 AppID", "Official Account App ID") }}
|
||||||
type="password"
|
</label>
|
||||||
class="input font-mono text-sm"
|
<input
|
||||||
:placeholder="
|
v-model="form.wechat_connect_mp_app_id"
|
||||||
form.wechat_connect_app_secret_configured
|
type="text"
|
||||||
? t('admin.settings.wechatConnect.appSecretConfiguredPlaceholder')
|
class="input font-mono text-sm"
|
||||||
: t('admin.settings.wechatConnect.appSecretPlaceholder')
|
:placeholder="
|
||||||
"
|
localText(
|
||||||
/>
|
'公众号 AppID',
|
||||||
<p class="mt-1.5 text-xs text-gray-500 dark:text-gray-400">
|
'Official Account App ID',
|
||||||
{{
|
)
|
||||||
form.wechat_connect_app_secret_configured
|
"
|
||||||
? t('admin.settings.wechatConnect.appSecretConfiguredHint')
|
/>
|
||||||
: t('admin.settings.wechatConnect.appSecretHint')
|
</div>
|
||||||
}}
|
<div>
|
||||||
</p>
|
<label
|
||||||
|
class="mb-2 block text-sm font-medium text-gray-700 dark:text-gray-300"
|
||||||
|
>
|
||||||
|
{{
|
||||||
|
localText(
|
||||||
|
"公众号 AppSecret",
|
||||||
|
"Official Account App Secret",
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
v-model="form.wechat_connect_mp_app_secret"
|
||||||
|
type="password"
|
||||||
|
class="input font-mono text-sm"
|
||||||
|
:placeholder="
|
||||||
|
form.wechat_connect_mp_app_secret_configured
|
||||||
|
? localText(
|
||||||
|
'密钥已配置,留空以保留当前值。',
|
||||||
|
'Secret configured. Leave empty to keep the current value.',
|
||||||
|
)
|
||||||
|
: localText(
|
||||||
|
'公众号 AppSecret',
|
||||||
|
'Official Account App Secret',
|
||||||
|
)
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
class="rounded-lg border border-gray-200 p-4 dark:border-dark-700"
|
||||||
|
>
|
||||||
|
<div class="flex items-start justify-between gap-4">
|
||||||
|
<div>
|
||||||
|
<h3 class="font-medium text-gray-900 dark:text-white">
|
||||||
|
{{ localText("移动应用", "Mobile App") }}
|
||||||
|
</h3>
|
||||||
|
<p class="mt-1 text-sm text-gray-500 dark:text-gray-400">
|
||||||
|
{{
|
||||||
|
localText(
|
||||||
|
"原生移动端通过微信 SDK 唤起授权,网页端不会直接发起该流程。",
|
||||||
|
"Native mobile clients start authorization through the WeChat SDK. The web UI does not launch this flow directly.",
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<Toggle
|
||||||
|
:model-value="form.wechat_connect_mobile_enabled"
|
||||||
|
data-testid="wechat-connect-mobile-enabled"
|
||||||
|
@update:model-value="handleWeChatMobileEnabledChange"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
v-if="form.wechat_connect_mobile_enabled"
|
||||||
|
class="mt-4 grid grid-cols-1 gap-4 lg:grid-cols-2"
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
<label
|
||||||
|
class="mb-2 block text-sm font-medium text-gray-700 dark:text-gray-300"
|
||||||
|
>
|
||||||
|
{{ localText("移动应用 AppID", "Mobile App ID") }}
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
v-model="form.wechat_connect_mobile_app_id"
|
||||||
|
type="text"
|
||||||
|
class="input font-mono text-sm"
|
||||||
|
:placeholder="
|
||||||
|
localText(
|
||||||
|
'移动应用 AppID',
|
||||||
|
'Mobile App ID',
|
||||||
|
)
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label
|
||||||
|
class="mb-2 block text-sm font-medium text-gray-700 dark:text-gray-300"
|
||||||
|
>
|
||||||
|
{{ localText("移动应用 AppSecret", "Mobile App Secret") }}
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
v-model="form.wechat_connect_mobile_app_secret"
|
||||||
|
type="password"
|
||||||
|
class="input font-mono text-sm"
|
||||||
|
:placeholder="
|
||||||
|
form.wechat_connect_mobile_app_secret_configured
|
||||||
|
? localText(
|
||||||
|
'密钥已配置,留空以保留当前值。',
|
||||||
|
'Secret configured. Leave empty to keep the current value.',
|
||||||
|
)
|
||||||
|
: localText(
|
||||||
|
'移动应用 AppSecret',
|
||||||
|
'Mobile App Secret',
|
||||||
|
)
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="grid grid-cols-1 gap-6 lg:grid-cols-2">
|
<div
|
||||||
<div class="space-y-3">
|
v-if="
|
||||||
<label
|
form.wechat_connect_open_enabled &&
|
||||||
class="mb-2 block text-sm font-medium text-gray-700 dark:text-gray-300"
|
(form.wechat_connect_mp_enabled ||
|
||||||
>
|
form.wechat_connect_mobile_enabled)
|
||||||
{{ t("admin.settings.wechatConnect.modeLabel") }}
|
"
|
||||||
</label>
|
class="rounded-lg border border-amber-200 bg-amber-50 px-4 py-3 text-sm text-amber-700 dark:border-amber-900/40 dark:bg-amber-900/10 dark:text-amber-300"
|
||||||
<div
|
>
|
||||||
class="flex items-center justify-between rounded border border-gray-200 px-4 py-3 dark:border-dark-700"
|
{{
|
||||||
>
|
localText(
|
||||||
<div>
|
"如果同时启用 PC 应用和公众号/移动应用,这些应用需要挂在同一个微信开放平台主体下,否则 UnionID 无法稳定归并账号。",
|
||||||
<div class="font-medium text-gray-900 dark:text-white">
|
"When PC App is enabled together with Official Account or Mobile App, they should belong to the same WeChat Open Platform account so UnionID can merge identities reliably.",
|
||||||
{{ t("admin.settings.wechatConnect.openModeLabel") }}
|
)
|
||||||
</div>
|
}}
|
||||||
<p
|
</div>
|
||||||
class="mt-0.5 text-xs text-gray-500 dark:text-gray-400"
|
|
||||||
>
|
|
||||||
{{ t("admin.settings.wechatConnect.openModeHint") }}
|
|
||||||
</p>
|
|
||||||
</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">
|
|
||||||
{{ t("admin.settings.wechatConnect.mpModeLabel") }}
|
|
||||||
</div>
|
|
||||||
<p
|
|
||||||
class="mt-0.5 text-xs text-gray-500 dark:text-gray-400"
|
|
||||||
>
|
|
||||||
{{ t("admin.settings.wechatConnect.mpModeHint") }}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<Toggle
|
|
||||||
v-model="form.wechat_connect_mp_enabled"
|
|
||||||
data-testid="wechat-connect-mp-enabled"
|
|
||||||
@update:model-value="syncWeChatConnectMode"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
<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"
|
||||||
>
|
>
|
||||||
{{ t("admin.settings.wechatConnect.redirectUrlLabel") }}
|
{{
|
||||||
|
localText(
|
||||||
|
"浏览器回调地址",
|
||||||
|
"Browser Redirect URL",
|
||||||
|
)
|
||||||
|
}}
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
data-testid="wechat-connect-redirect-url"
|
data-testid="wechat-connect-redirect-url"
|
||||||
@@ -1501,6 +1653,14 @@
|
|||||||
class="input font-mono text-sm"
|
class="input font-mono text-sm"
|
||||||
:placeholder="t('admin.settings.wechatConnect.redirectUrlPlaceholder')"
|
:placeholder="t('admin.settings.wechatConnect.redirectUrlPlaceholder')"
|
||||||
/>
|
/>
|
||||||
|
<p class="mt-1.5 text-xs text-gray-500 dark:text-gray-400">
|
||||||
|
{{
|
||||||
|
localText(
|
||||||
|
"用于 PC 应用和公众号的网页回调。移动应用走原生 SDK 时不直接使用这个浏览器回调。",
|
||||||
|
"Used by PC App and Official Account browser callbacks. Native mobile SDK flows do not start from this browser callback directly.",
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
</p>
|
||||||
<div
|
<div
|
||||||
class="mt-2 flex flex-col gap-2 sm:flex-row sm:items-center sm:gap-3"
|
class="mt-2 flex flex-col gap-2 sm:flex-row sm:items-center sm:gap-3"
|
||||||
>
|
>
|
||||||
@@ -4594,6 +4754,7 @@ import type {
|
|||||||
SystemSettings,
|
SystemSettings,
|
||||||
UpdateSettingsRequest,
|
UpdateSettingsRequest,
|
||||||
DefaultSubscriptionSetting,
|
DefaultSubscriptionSetting,
|
||||||
|
WeChatConnectMode,
|
||||||
WebSearchEmulationConfig,
|
WebSearchEmulationConfig,
|
||||||
WebSearchProviderConfig,
|
WebSearchProviderConfig,
|
||||||
WebSearchTestResult,
|
WebSearchTestResult,
|
||||||
@@ -4731,14 +4892,20 @@ interface DefaultSubscriptionGroupOption {
|
|||||||
|
|
||||||
type SettingsForm = Omit<
|
type SettingsForm = Omit<
|
||||||
SystemSettings,
|
SystemSettings,
|
||||||
"wechat_connect_open_enabled" | "wechat_connect_mp_enabled"
|
| "wechat_connect_open_enabled"
|
||||||
|
| "wechat_connect_mp_enabled"
|
||||||
|
| "wechat_connect_mobile_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_app_secret: string;
|
||||||
|
wechat_connect_mp_app_secret: string;
|
||||||
|
wechat_connect_mobile_app_secret: string;
|
||||||
wechat_connect_open_enabled: boolean;
|
wechat_connect_open_enabled: boolean;
|
||||||
wechat_connect_mp_enabled: boolean;
|
wechat_connect_mp_enabled: boolean;
|
||||||
|
wechat_connect_mobile_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;
|
||||||
@@ -4833,8 +5000,18 @@ 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_app_id: "",
|
||||||
|
wechat_connect_open_app_secret: "",
|
||||||
|
wechat_connect_open_app_secret_configured: false,
|
||||||
|
wechat_connect_mp_app_id: "",
|
||||||
|
wechat_connect_mp_app_secret: "",
|
||||||
|
wechat_connect_mp_app_secret_configured: false,
|
||||||
|
wechat_connect_mobile_app_id: "",
|
||||||
|
wechat_connect_mobile_app_secret: "",
|
||||||
|
wechat_connect_mobile_app_secret_configured: false,
|
||||||
wechat_connect_open_enabled: false,
|
wechat_connect_open_enabled: false,
|
||||||
wechat_connect_mp_enabled: false,
|
wechat_connect_mp_enabled: false,
|
||||||
|
wechat_connect_mobile_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: "",
|
||||||
@@ -5315,17 +5492,28 @@ const wechatRedirectUrlSuggestion = computed(() => {
|
|||||||
return `${origin}/api/v1/auth/oauth/wechat/callback`;
|
return `${origin}/api/v1/auth/oauth/wechat/callback`;
|
||||||
});
|
});
|
||||||
|
|
||||||
function syncWeChatConnectMode() {
|
function syncWeChatConnectMode(preferredMode?: WeChatConnectMode) {
|
||||||
|
if (form.wechat_connect_mp_enabled && form.wechat_connect_mobile_enabled) {
|
||||||
|
if (preferredMode === "mobile") {
|
||||||
|
form.wechat_connect_mp_enabled = false;
|
||||||
|
} else {
|
||||||
|
form.wechat_connect_mobile_enabled = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const capabilities = resolveWeChatConnectModeCapabilities(
|
const capabilities = resolveWeChatConnectModeCapabilities(
|
||||||
form.wechat_connect_open_enabled,
|
form.wechat_connect_open_enabled,
|
||||||
form.wechat_connect_mp_enabled,
|
form.wechat_connect_mp_enabled,
|
||||||
|
form.wechat_connect_mobile_enabled,
|
||||||
form.wechat_connect_mode,
|
form.wechat_connect_mode,
|
||||||
);
|
);
|
||||||
form.wechat_connect_open_enabled = capabilities.openEnabled;
|
form.wechat_connect_open_enabled = capabilities.openEnabled;
|
||||||
form.wechat_connect_mp_enabled = capabilities.mpEnabled;
|
form.wechat_connect_mp_enabled = capabilities.mpEnabled;
|
||||||
|
form.wechat_connect_mobile_enabled = capabilities.mobileEnabled;
|
||||||
form.wechat_connect_mode = deriveWeChatConnectStoredMode(
|
form.wechat_connect_mode = deriveWeChatConnectStoredMode(
|
||||||
capabilities.openEnabled,
|
capabilities.openEnabled,
|
||||||
capabilities.mpEnabled,
|
capabilities.mpEnabled,
|
||||||
|
capabilities.mobileEnabled,
|
||||||
form.wechat_connect_mode,
|
form.wechat_connect_mode,
|
||||||
);
|
);
|
||||||
form.wechat_connect_scopes = defaultWeChatConnectScopesForMode(
|
form.wechat_connect_scopes = defaultWeChatConnectScopesForMode(
|
||||||
@@ -5333,6 +5521,27 @@ function syncWeChatConnectMode() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleWeChatOpenEnabledChange(value: boolean) {
|
||||||
|
form.wechat_connect_open_enabled = value;
|
||||||
|
syncWeChatConnectMode(value ? "open" : undefined);
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleWeChatMPEnabledChange(value: boolean) {
|
||||||
|
form.wechat_connect_mp_enabled = value;
|
||||||
|
if (value) {
|
||||||
|
form.wechat_connect_mobile_enabled = false;
|
||||||
|
}
|
||||||
|
syncWeChatConnectMode(value ? "mp" : undefined);
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleWeChatMobileEnabledChange(value: boolean) {
|
||||||
|
form.wechat_connect_mobile_enabled = value;
|
||||||
|
if (value) {
|
||||||
|
form.wechat_connect_mp_enabled = false;
|
||||||
|
}
|
||||||
|
syncWeChatConnectMode(value ? "mobile" : undefined);
|
||||||
|
}
|
||||||
|
|
||||||
async function setAndCopyWeChatRedirectUrl() {
|
async function setAndCopyWeChatRedirectUrl() {
|
||||||
const url = wechatRedirectUrlSuggestion.value;
|
const url = wechatRedirectUrlSuggestion.value;
|
||||||
if (!url) return;
|
if (!url) return;
|
||||||
@@ -5476,16 +5685,22 @@ 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_open_app_secret = "";
|
||||||
|
form.wechat_connect_mp_app_secret = "";
|
||||||
|
form.wechat_connect_mobile_app_secret = "";
|
||||||
const wechatCapabilities = resolveWeChatConnectModeCapabilities(
|
const wechatCapabilities = resolveWeChatConnectModeCapabilities(
|
||||||
settings.wechat_connect_open_enabled,
|
settings.wechat_connect_open_enabled,
|
||||||
settings.wechat_connect_mp_enabled,
|
settings.wechat_connect_mp_enabled,
|
||||||
|
settings.wechat_connect_mobile_enabled,
|
||||||
settings.wechat_connect_mode,
|
settings.wechat_connect_mode,
|
||||||
);
|
);
|
||||||
form.wechat_connect_open_enabled = wechatCapabilities.openEnabled;
|
form.wechat_connect_open_enabled = wechatCapabilities.openEnabled;
|
||||||
form.wechat_connect_mp_enabled = wechatCapabilities.mpEnabled;
|
form.wechat_connect_mp_enabled = wechatCapabilities.mpEnabled;
|
||||||
|
form.wechat_connect_mobile_enabled = wechatCapabilities.mobileEnabled;
|
||||||
form.wechat_connect_mode = deriveWeChatConnectStoredMode(
|
form.wechat_connect_mode = deriveWeChatConnectStoredMode(
|
||||||
wechatCapabilities.openEnabled,
|
wechatCapabilities.openEnabled,
|
||||||
wechatCapabilities.mpEnabled,
|
wechatCapabilities.mpEnabled,
|
||||||
|
wechatCapabilities.mobileEnabled,
|
||||||
settings.wechat_connect_mode,
|
settings.wechat_connect_mode,
|
||||||
);
|
);
|
||||||
form.wechat_connect_scopes = defaultWeChatConnectScopesForMode(
|
form.wechat_connect_scopes = defaultWeChatConnectScopesForMode(
|
||||||
@@ -5649,6 +5864,16 @@ async function saveSettings() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (form.wechat_connect_mp_enabled && form.wechat_connect_mobile_enabled) {
|
||||||
|
appStore.showError(
|
||||||
|
localText(
|
||||||
|
"公众号和移动应用不能同时启用。",
|
||||||
|
"Official Account and Mobile App cannot be enabled at the same time.",
|
||||||
|
),
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Validate URL fields — novalidate disables browser-native checks, so we validate here
|
// Validate URL fields — novalidate disables browser-native checks, so we validate here
|
||||||
const isValidHttpUrl = (url: string): boolean => {
|
const isValidHttpUrl = (url: string): boolean => {
|
||||||
if (!url) return true;
|
if (!url) return true;
|
||||||
@@ -5666,6 +5891,7 @@ async function saveSettings() {
|
|||||||
const wechatStoredMode = deriveWeChatConnectStoredMode(
|
const wechatStoredMode = deriveWeChatConnectStoredMode(
|
||||||
form.wechat_connect_open_enabled,
|
form.wechat_connect_open_enabled,
|
||||||
form.wechat_connect_mp_enabled,
|
form.wechat_connect_mp_enabled,
|
||||||
|
form.wechat_connect_mobile_enabled,
|
||||||
form.wechat_connect_mode,
|
form.wechat_connect_mode,
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -5714,10 +5940,24 @@ async function saveSettings() {
|
|||||||
form.linuxdo_connect_client_secret || undefined,
|
form.linuxdo_connect_client_secret || undefined,
|
||||||
linuxdo_connect_redirect_url: form.linuxdo_connect_redirect_url,
|
linuxdo_connect_redirect_url: form.linuxdo_connect_redirect_url,
|
||||||
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_open_app_id ||
|
||||||
|
form.wechat_connect_mp_app_id ||
|
||||||
|
form.wechat_connect_mobile_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_open_app_id: form.wechat_connect_open_app_id,
|
||||||
|
wechat_connect_open_app_secret:
|
||||||
|
form.wechat_connect_open_app_secret || undefined,
|
||||||
|
wechat_connect_mp_app_id: form.wechat_connect_mp_app_id,
|
||||||
|
wechat_connect_mp_app_secret:
|
||||||
|
form.wechat_connect_mp_app_secret || undefined,
|
||||||
|
wechat_connect_mobile_app_id: form.wechat_connect_mobile_app_id,
|
||||||
|
wechat_connect_mobile_app_secret:
|
||||||
|
form.wechat_connect_mobile_app_secret || undefined,
|
||||||
wechat_connect_open_enabled: form.wechat_connect_open_enabled,
|
wechat_connect_open_enabled: form.wechat_connect_open_enabled,
|
||||||
wechat_connect_mp_enabled: form.wechat_connect_mp_enabled,
|
wechat_connect_mp_enabled: form.wechat_connect_mp_enabled,
|
||||||
|
wechat_connect_mobile_enabled: form.wechat_connect_mobile_enabled,
|
||||||
wechat_connect_mode: wechatStoredMode,
|
wechat_connect_mode: wechatStoredMode,
|
||||||
wechat_connect_scopes:
|
wechat_connect_scopes:
|
||||||
defaultWeChatConnectScopesForMode(wechatStoredMode),
|
defaultWeChatConnectScopesForMode(wechatStoredMode),
|
||||||
@@ -5847,16 +6087,23 @@ 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_open_app_secret = "";
|
||||||
|
form.wechat_connect_mp_app_secret = "";
|
||||||
|
form.wechat_connect_mobile_app_secret = "";
|
||||||
const updatedWechatCapabilities = resolveWeChatConnectModeCapabilities(
|
const updatedWechatCapabilities = resolveWeChatConnectModeCapabilities(
|
||||||
updated.wechat_connect_open_enabled,
|
updated.wechat_connect_open_enabled,
|
||||||
updated.wechat_connect_mp_enabled,
|
updated.wechat_connect_mp_enabled,
|
||||||
|
updated.wechat_connect_mobile_enabled,
|
||||||
updated.wechat_connect_mode,
|
updated.wechat_connect_mode,
|
||||||
);
|
);
|
||||||
form.wechat_connect_open_enabled = updatedWechatCapabilities.openEnabled;
|
form.wechat_connect_open_enabled = updatedWechatCapabilities.openEnabled;
|
||||||
form.wechat_connect_mp_enabled = updatedWechatCapabilities.mpEnabled;
|
form.wechat_connect_mp_enabled = updatedWechatCapabilities.mpEnabled;
|
||||||
|
form.wechat_connect_mobile_enabled =
|
||||||
|
updatedWechatCapabilities.mobileEnabled;
|
||||||
form.wechat_connect_mode = deriveWeChatConnectStoredMode(
|
form.wechat_connect_mode = deriveWeChatConnectStoredMode(
|
||||||
updatedWechatCapabilities.openEnabled,
|
updatedWechatCapabilities.openEnabled,
|
||||||
updatedWechatCapabilities.mpEnabled,
|
updatedWechatCapabilities.mpEnabled,
|
||||||
|
updatedWechatCapabilities.mobileEnabled,
|
||||||
updated.wechat_connect_mode,
|
updated.wechat_connect_mode,
|
||||||
);
|
);
|
||||||
form.wechat_connect_scopes = defaultWeChatConnectScopesForMode(
|
form.wechat_connect_scopes = defaultWeChatConnectScopesForMode(
|
||||||
|
|||||||
@@ -184,7 +184,7 @@ import TotpLoginModal from '@/components/auth/TotpLoginModal.vue'
|
|||||||
import Icon from '@/components/icons/Icon.vue'
|
import Icon from '@/components/icons/Icon.vue'
|
||||||
import TurnstileWidget from '@/components/TurnstileWidget.vue'
|
import TurnstileWidget from '@/components/TurnstileWidget.vue'
|
||||||
import { useAuthStore, useAppStore } from '@/stores'
|
import { useAuthStore, useAppStore } from '@/stores'
|
||||||
import { getPublicSettings, isTotp2FARequired } from '@/api/auth'
|
import { getPublicSettings, isTotp2FARequired, isWeChatWebOAuthEnabled } from '@/api/auth'
|
||||||
import type { TotpLoginResponse } from '@/types'
|
import type { TotpLoginResponse } from '@/types'
|
||||||
|
|
||||||
const { t } = useI18n()
|
const { t } = useI18n()
|
||||||
@@ -258,7 +258,7 @@ onMounted(async () => {
|
|||||||
turnstileEnabled.value = settings.turnstile_enabled
|
turnstileEnabled.value = settings.turnstile_enabled
|
||||||
turnstileSiteKey.value = settings.turnstile_site_key || ''
|
turnstileSiteKey.value = settings.turnstile_site_key || ''
|
||||||
linuxdoOAuthEnabled.value = settings.linuxdo_oauth_enabled
|
linuxdoOAuthEnabled.value = settings.linuxdo_oauth_enabled
|
||||||
wechatOAuthEnabled.value = settings.wechat_oauth_enabled
|
wechatOAuthEnabled.value = isWeChatWebOAuthEnabled(settings)
|
||||||
backendModeEnabled.value = settings.backend_mode_enabled
|
backendModeEnabled.value = settings.backend_mode_enabled
|
||||||
oidcOAuthEnabled.value = settings.oidc_oauth_enabled
|
oidcOAuthEnabled.value = settings.oidc_oauth_enabled
|
||||||
oidcOAuthProviderName.value = settings.oidc_oauth_provider_name || 'OIDC'
|
oidcOAuthProviderName.value = settings.oidc_oauth_provider_name || 'OIDC'
|
||||||
|
|||||||
@@ -282,7 +282,12 @@ import WechatOAuthSection from '@/components/auth/WechatOAuthSection.vue'
|
|||||||
import Icon from '@/components/icons/Icon.vue'
|
import Icon from '@/components/icons/Icon.vue'
|
||||||
import TurnstileWidget from '@/components/TurnstileWidget.vue'
|
import TurnstileWidget from '@/components/TurnstileWidget.vue'
|
||||||
import { useAuthStore, useAppStore } from '@/stores'
|
import { useAuthStore, useAppStore } from '@/stores'
|
||||||
import { getPublicSettings, validatePromoCode, validateInvitationCode } from '@/api/auth'
|
import {
|
||||||
|
getPublicSettings,
|
||||||
|
isWeChatWebOAuthEnabled,
|
||||||
|
validatePromoCode,
|
||||||
|
validateInvitationCode
|
||||||
|
} from '@/api/auth'
|
||||||
import { buildAuthErrorMessage } from '@/utils/authError'
|
import { buildAuthErrorMessage } from '@/utils/authError'
|
||||||
import {
|
import {
|
||||||
isRegistrationEmailSuffixAllowed,
|
isRegistrationEmailSuffixAllowed,
|
||||||
@@ -385,7 +390,7 @@ onMounted(async () => {
|
|||||||
turnstileSiteKey.value = settings.turnstile_site_key || ''
|
turnstileSiteKey.value = settings.turnstile_site_key || ''
|
||||||
siteName.value = settings.site_name || 'Sub2API'
|
siteName.value = settings.site_name || 'Sub2API'
|
||||||
linuxdoOAuthEnabled.value = settings.linuxdo_oauth_enabled
|
linuxdoOAuthEnabled.value = settings.linuxdo_oauth_enabled
|
||||||
wechatOAuthEnabled.value = settings.wechat_oauth_enabled
|
wechatOAuthEnabled.value = isWeChatWebOAuthEnabled(settings)
|
||||||
oidcOAuthEnabled.value = settings.oidc_oauth_enabled
|
oidcOAuthEnabled.value = settings.oidc_oauth_enabled
|
||||||
oidcOAuthProviderName.value = settings.oidc_oauth_provider_name || 'OIDC'
|
oidcOAuthProviderName.value = settings.oidc_oauth_provider_name || 'OIDC'
|
||||||
registrationEmailSuffixWhitelist.value = normalizeRegistrationEmailSuffixWhitelist(
|
registrationEmailSuffixWhitelist.value = normalizeRegistrationEmailSuffixWhitelist(
|
||||||
|
|||||||
@@ -504,6 +504,8 @@ function resolveWeChatOAuthUnavailableMessage(): string {
|
|||||||
return t('auth.oauthFlow.wechatSystemBrowserOnly')
|
return t('auth.oauthFlow.wechatSystemBrowserOnly')
|
||||||
case 'wechat_browser_required':
|
case 'wechat_browser_required':
|
||||||
return t('auth.oauthFlow.wechatBrowserOnly')
|
return t('auth.oauthFlow.wechatBrowserOnly')
|
||||||
|
case 'native_app_required':
|
||||||
|
return 'This WeChat sign-in flow is only available from the native mobile app.'
|
||||||
case 'not_configured':
|
case 'not_configured':
|
||||||
return t('auth.oauthFlow.wechatNotConfigured')
|
return t('auth.oauthFlow.wechatNotConfigured')
|
||||||
default:
|
default:
|
||||||
|
|||||||
Reference in New Issue
Block a user