diff --git a/backend/cmd/server/wire_gen.go b/backend/cmd/server/wire_gen.go index 7b7ec0e6..fdc5c6ac 100644 --- a/backend/cmd/server/wire_gen.go +++ b/backend/cmd/server/wire_gen.go @@ -142,7 +142,7 @@ func initializeApplication(buildInfo handler.BuildInfo) (*Application, error) { tlsFingerprintProfileCache := repository.NewTLSFingerprintProfileCache(redisClient) tlsFingerprintProfileService := service.NewTLSFingerprintProfileService(tlsFingerprintProfileRepository, tlsFingerprintProfileCache) accountUsageService := service.NewAccountUsageService(accountRepository, usageLogRepository, claudeUsageFetcher, geminiQuotaService, antigravityQuotaFetcher, usageCache, identityCache, tlsFingerprintProfileService) - antigravityGatewayService := service.NewAntigravityGatewayService(accountRepository, gatewayCache, schedulerSnapshotService, antigravityTokenProvider, rateLimitService, httpUpstream, settingService, internal500CounterCache, accountUsageService) + antigravityGatewayService := service.NewAntigravityGatewayService(accountRepository, gatewayCache, schedulerSnapshotService, antigravityTokenProvider, rateLimitService, httpUpstream, settingService, internal500CounterCache) accountTestService := service.NewAccountTestService(accountRepository, geminiTokenProvider, antigravityGatewayService, httpUpstream, configConfig, tlsFingerprintProfileService) crsSyncService := service.NewCRSSyncService(accountRepository, proxyRepository, oAuthService, openAIOAuthService, geminiOAuthService, configConfig) sessionLimitCache := repository.ProvideSessionLimitCache(redisClient, configConfig) diff --git a/backend/internal/handler/admin/setting_handler.go b/backend/internal/handler/admin/setting_handler.go index 5d625942..06916917 100644 --- a/backend/internal/handler/admin/setting_handler.go +++ b/backend/internal/handler/admin/setting_handler.go @@ -41,17 +41,15 @@ type SettingHandler struct { emailService *service.EmailService turnstileService *service.TurnstileService opsService *service.OpsService - soraS3Storage *service.SoraS3Storage } // NewSettingHandler 创建系统设置处理器 -func NewSettingHandler(settingService *service.SettingService, emailService *service.EmailService, turnstileService *service.TurnstileService, opsService *service.OpsService, soraS3Storage *service.SoraS3Storage) *SettingHandler { +func NewSettingHandler(settingService *service.SettingService, emailService *service.EmailService, turnstileService *service.TurnstileService, opsService *service.OpsService) *SettingHandler { return &SettingHandler{ settingService: settingService, emailService: emailService, turnstileService: turnstileService, opsService: opsService, - soraS3Storage: soraS3Storage, } } @@ -1203,384 +1201,6 @@ func (h *SettingHandler) GetStreamTimeoutSettings(c *gin.Context) { }) } -func toSoraS3SettingsDTO(settings *service.SoraS3Settings) dto.SoraS3Settings { - if settings == nil { - return dto.SoraS3Settings{} - } - return dto.SoraS3Settings{ - Enabled: settings.Enabled, - Endpoint: settings.Endpoint, - Region: settings.Region, - Bucket: settings.Bucket, - AccessKeyID: settings.AccessKeyID, - SecretAccessKeyConfigured: settings.SecretAccessKeyConfigured, - Prefix: settings.Prefix, - ForcePathStyle: settings.ForcePathStyle, - CDNURL: settings.CDNURL, - DefaultStorageQuotaBytes: settings.DefaultStorageQuotaBytes, - } -} - -func toSoraS3ProfileDTO(profile service.SoraS3Profile) dto.SoraS3Profile { - return dto.SoraS3Profile{ - ProfileID: profile.ProfileID, - Name: profile.Name, - IsActive: profile.IsActive, - Enabled: profile.Enabled, - Endpoint: profile.Endpoint, - Region: profile.Region, - Bucket: profile.Bucket, - AccessKeyID: profile.AccessKeyID, - SecretAccessKeyConfigured: profile.SecretAccessKeyConfigured, - Prefix: profile.Prefix, - ForcePathStyle: profile.ForcePathStyle, - CDNURL: profile.CDNURL, - DefaultStorageQuotaBytes: profile.DefaultStorageQuotaBytes, - UpdatedAt: profile.UpdatedAt, - } -} - -func validateSoraS3RequiredWhenEnabled(enabled bool, endpoint, bucket, accessKeyID, secretAccessKey string, hasStoredSecret bool) error { - if !enabled { - return nil - } - if strings.TrimSpace(endpoint) == "" { - return fmt.Errorf("S3 Endpoint is required when enabled") - } - if strings.TrimSpace(bucket) == "" { - return fmt.Errorf("S3 Bucket is required when enabled") - } - if strings.TrimSpace(accessKeyID) == "" { - return fmt.Errorf("S3 Access Key ID is required when enabled") - } - if strings.TrimSpace(secretAccessKey) != "" || hasStoredSecret { - return nil - } - return fmt.Errorf("S3 Secret Access Key is required when enabled") -} - -func findSoraS3ProfileByID(items []service.SoraS3Profile, profileID string) *service.SoraS3Profile { - for idx := range items { - if items[idx].ProfileID == profileID { - return &items[idx] - } - } - return nil -} - -// GetSoraS3Settings 获取 Sora S3 存储配置(兼容旧单配置接口) -// GET /api/v1/admin/settings/sora-s3 -func (h *SettingHandler) GetSoraS3Settings(c *gin.Context) { - settings, err := h.settingService.GetSoraS3Settings(c.Request.Context()) - if err != nil { - response.ErrorFrom(c, err) - return - } - response.Success(c, toSoraS3SettingsDTO(settings)) -} - -// ListSoraS3Profiles 获取 Sora S3 多配置 -// GET /api/v1/admin/settings/sora-s3/profiles -func (h *SettingHandler) ListSoraS3Profiles(c *gin.Context) { - result, err := h.settingService.ListSoraS3Profiles(c.Request.Context()) - if err != nil { - response.ErrorFrom(c, err) - return - } - items := make([]dto.SoraS3Profile, 0, len(result.Items)) - for idx := range result.Items { - items = append(items, toSoraS3ProfileDTO(result.Items[idx])) - } - response.Success(c, dto.ListSoraS3ProfilesResponse{ - ActiveProfileID: result.ActiveProfileID, - Items: items, - }) -} - -// UpdateSoraS3SettingsRequest 更新/测试 Sora S3 配置请求(兼容旧接口) -type UpdateSoraS3SettingsRequest struct { - ProfileID string `json:"profile_id"` - Enabled bool `json:"enabled"` - Endpoint string `json:"endpoint"` - Region string `json:"region"` - Bucket string `json:"bucket"` - AccessKeyID string `json:"access_key_id"` - SecretAccessKey string `json:"secret_access_key"` - Prefix string `json:"prefix"` - ForcePathStyle bool `json:"force_path_style"` - CDNURL string `json:"cdn_url"` - DefaultStorageQuotaBytes int64 `json:"default_storage_quota_bytes"` -} - -type CreateSoraS3ProfileRequest struct { - ProfileID string `json:"profile_id"` - Name string `json:"name"` - SetActive bool `json:"set_active"` - Enabled bool `json:"enabled"` - Endpoint string `json:"endpoint"` - Region string `json:"region"` - Bucket string `json:"bucket"` - AccessKeyID string `json:"access_key_id"` - SecretAccessKey string `json:"secret_access_key"` - Prefix string `json:"prefix"` - ForcePathStyle bool `json:"force_path_style"` - CDNURL string `json:"cdn_url"` - DefaultStorageQuotaBytes int64 `json:"default_storage_quota_bytes"` -} - -type UpdateSoraS3ProfileRequest struct { - Name string `json:"name"` - Enabled bool `json:"enabled"` - Endpoint string `json:"endpoint"` - Region string `json:"region"` - Bucket string `json:"bucket"` - AccessKeyID string `json:"access_key_id"` - SecretAccessKey string `json:"secret_access_key"` - Prefix string `json:"prefix"` - ForcePathStyle bool `json:"force_path_style"` - CDNURL string `json:"cdn_url"` - DefaultStorageQuotaBytes int64 `json:"default_storage_quota_bytes"` -} - -// CreateSoraS3Profile 创建 Sora S3 配置 -// POST /api/v1/admin/settings/sora-s3/profiles -func (h *SettingHandler) CreateSoraS3Profile(c *gin.Context) { - var req CreateSoraS3ProfileRequest - if err := c.ShouldBindJSON(&req); err != nil { - response.BadRequest(c, "Invalid request: "+err.Error()) - return - } - - if req.DefaultStorageQuotaBytes < 0 { - req.DefaultStorageQuotaBytes = 0 - } - if strings.TrimSpace(req.Name) == "" { - response.BadRequest(c, "Name is required") - return - } - if strings.TrimSpace(req.ProfileID) == "" { - response.BadRequest(c, "Profile ID is required") - return - } - if err := validateSoraS3RequiredWhenEnabled(req.Enabled, req.Endpoint, req.Bucket, req.AccessKeyID, req.SecretAccessKey, false); err != nil { - response.BadRequest(c, err.Error()) - return - } - - created, err := h.settingService.CreateSoraS3Profile(c.Request.Context(), &service.SoraS3Profile{ - ProfileID: req.ProfileID, - Name: req.Name, - Enabled: req.Enabled, - Endpoint: req.Endpoint, - Region: req.Region, - Bucket: req.Bucket, - AccessKeyID: req.AccessKeyID, - SecretAccessKey: req.SecretAccessKey, - Prefix: req.Prefix, - ForcePathStyle: req.ForcePathStyle, - CDNURL: req.CDNURL, - DefaultStorageQuotaBytes: req.DefaultStorageQuotaBytes, - }, req.SetActive) - if err != nil { - response.ErrorFrom(c, err) - return - } - - response.Success(c, toSoraS3ProfileDTO(*created)) -} - -// UpdateSoraS3Profile 更新 Sora S3 配置 -// PUT /api/v1/admin/settings/sora-s3/profiles/:profile_id -func (h *SettingHandler) UpdateSoraS3Profile(c *gin.Context) { - profileID := strings.TrimSpace(c.Param("profile_id")) - if profileID == "" { - response.BadRequest(c, "Profile ID is required") - return - } - - var req UpdateSoraS3ProfileRequest - if err := c.ShouldBindJSON(&req); err != nil { - response.BadRequest(c, "Invalid request: "+err.Error()) - return - } - - if req.DefaultStorageQuotaBytes < 0 { - req.DefaultStorageQuotaBytes = 0 - } - if strings.TrimSpace(req.Name) == "" { - response.BadRequest(c, "Name is required") - return - } - - existingList, err := h.settingService.ListSoraS3Profiles(c.Request.Context()) - if err != nil { - response.ErrorFrom(c, err) - return - } - existing := findSoraS3ProfileByID(existingList.Items, profileID) - if existing == nil { - response.ErrorFrom(c, service.ErrSoraS3ProfileNotFound) - return - } - if err := validateSoraS3RequiredWhenEnabled(req.Enabled, req.Endpoint, req.Bucket, req.AccessKeyID, req.SecretAccessKey, existing.SecretAccessKeyConfigured); err != nil { - response.BadRequest(c, err.Error()) - return - } - - updated, updateErr := h.settingService.UpdateSoraS3Profile(c.Request.Context(), profileID, &service.SoraS3Profile{ - Name: req.Name, - Enabled: req.Enabled, - Endpoint: req.Endpoint, - Region: req.Region, - Bucket: req.Bucket, - AccessKeyID: req.AccessKeyID, - SecretAccessKey: req.SecretAccessKey, - Prefix: req.Prefix, - ForcePathStyle: req.ForcePathStyle, - CDNURL: req.CDNURL, - DefaultStorageQuotaBytes: req.DefaultStorageQuotaBytes, - }) - if updateErr != nil { - response.ErrorFrom(c, updateErr) - return - } - - response.Success(c, toSoraS3ProfileDTO(*updated)) -} - -// DeleteSoraS3Profile 删除 Sora S3 配置 -// DELETE /api/v1/admin/settings/sora-s3/profiles/:profile_id -func (h *SettingHandler) DeleteSoraS3Profile(c *gin.Context) { - profileID := strings.TrimSpace(c.Param("profile_id")) - if profileID == "" { - response.BadRequest(c, "Profile ID is required") - return - } - if err := h.settingService.DeleteSoraS3Profile(c.Request.Context(), profileID); err != nil { - response.ErrorFrom(c, err) - return - } - response.Success(c, gin.H{"deleted": true}) -} - -// SetActiveSoraS3Profile 切换激活 Sora S3 配置 -// POST /api/v1/admin/settings/sora-s3/profiles/:profile_id/activate -func (h *SettingHandler) SetActiveSoraS3Profile(c *gin.Context) { - profileID := strings.TrimSpace(c.Param("profile_id")) - if profileID == "" { - response.BadRequest(c, "Profile ID is required") - return - } - active, err := h.settingService.SetActiveSoraS3Profile(c.Request.Context(), profileID) - if err != nil { - response.ErrorFrom(c, err) - return - } - response.Success(c, toSoraS3ProfileDTO(*active)) -} - -// UpdateSoraS3Settings 更新 Sora S3 存储配置(兼容旧单配置接口) -// PUT /api/v1/admin/settings/sora-s3 -func (h *SettingHandler) UpdateSoraS3Settings(c *gin.Context) { - var req UpdateSoraS3SettingsRequest - if err := c.ShouldBindJSON(&req); err != nil { - response.BadRequest(c, "Invalid request: "+err.Error()) - return - } - - existing, err := h.settingService.GetSoraS3Settings(c.Request.Context()) - if err != nil { - response.ErrorFrom(c, err) - return - } - - if req.DefaultStorageQuotaBytes < 0 { - req.DefaultStorageQuotaBytes = 0 - } - if err := validateSoraS3RequiredWhenEnabled(req.Enabled, req.Endpoint, req.Bucket, req.AccessKeyID, req.SecretAccessKey, existing.SecretAccessKeyConfigured); err != nil { - response.BadRequest(c, err.Error()) - return - } - - settings := &service.SoraS3Settings{ - Enabled: req.Enabled, - Endpoint: req.Endpoint, - Region: req.Region, - Bucket: req.Bucket, - AccessKeyID: req.AccessKeyID, - SecretAccessKey: req.SecretAccessKey, - Prefix: req.Prefix, - ForcePathStyle: req.ForcePathStyle, - CDNURL: req.CDNURL, - DefaultStorageQuotaBytes: req.DefaultStorageQuotaBytes, - } - if err := h.settingService.SetSoraS3Settings(c.Request.Context(), settings); err != nil { - response.ErrorFrom(c, err) - return - } - - updatedSettings, err := h.settingService.GetSoraS3Settings(c.Request.Context()) - if err != nil { - response.ErrorFrom(c, err) - return - } - response.Success(c, toSoraS3SettingsDTO(updatedSettings)) -} - -// TestSoraS3Connection 测试 Sora S3 连接(HeadBucket) -// POST /api/v1/admin/settings/sora-s3/test -func (h *SettingHandler) TestSoraS3Connection(c *gin.Context) { - if h.soraS3Storage == nil { - response.Error(c, 500, "S3 存储服务未初始化") - return - } - - var req UpdateSoraS3SettingsRequest - if err := c.ShouldBindJSON(&req); err != nil { - response.BadRequest(c, "Invalid request: "+err.Error()) - return - } - if !req.Enabled { - response.BadRequest(c, "S3 未启用,无法测试连接") - return - } - - if req.SecretAccessKey == "" { - if req.ProfileID != "" { - profiles, err := h.settingService.ListSoraS3Profiles(c.Request.Context()) - if err == nil { - profile := findSoraS3ProfileByID(profiles.Items, req.ProfileID) - if profile != nil { - req.SecretAccessKey = profile.SecretAccessKey - } - } - } - if req.SecretAccessKey == "" { - existing, err := h.settingService.GetSoraS3Settings(c.Request.Context()) - if err == nil { - req.SecretAccessKey = existing.SecretAccessKey - } - } - } - - testCfg := &service.SoraS3Settings{ - Enabled: true, - Endpoint: req.Endpoint, - Region: req.Region, - Bucket: req.Bucket, - AccessKeyID: req.AccessKeyID, - SecretAccessKey: req.SecretAccessKey, - Prefix: req.Prefix, - ForcePathStyle: req.ForcePathStyle, - CDNURL: req.CDNURL, - } - if err := h.soraS3Storage.TestConnectionWithSettings(c.Request.Context(), testCfg); err != nil { - response.Error(c, 400, "S3 连接测试失败: "+err.Error()) - return - } - response.Success(c, gin.H{"message": "S3 连接成功"}) -} - // GetRectifierSettings 获取请求整流器配置 // GET /api/v1/admin/settings/rectifier func (h *SettingHandler) GetRectifierSettings(c *gin.Context) { diff --git a/backend/internal/repository/api_key_repo.go b/backend/internal/repository/api_key_repo.go index b3b12e81..a1f83b83 100644 --- a/backend/internal/repository/api_key_repo.go +++ b/backend/internal/repository/api_key_repo.go @@ -651,8 +651,6 @@ func groupEntityToService(g *dbent.Group) *service.Group { SupportedModelScopes: g.SupportedModelScopes, SortOrder: g.SortOrder, AllowMessagesDispatch: g.AllowMessagesDispatch, - RequireOAuthOnly: g.RequireOauthOnly, - RequirePrivacySet: g.RequirePrivacySet, DefaultMappedModel: g.DefaultMappedModel, CreatedAt: g.CreatedAt, UpdatedAt: g.UpdatedAt, diff --git a/backend/internal/repository/group_repo.go b/backend/internal/repository/group_repo.go index a075b586..9cae50e6 100644 --- a/backend/internal/repository/group_repo.go +++ b/backend/internal/repository/group_repo.go @@ -56,8 +56,6 @@ func (r *groupRepository) Create(ctx context.Context, groupIn *service.Group) er SetModelRoutingEnabled(groupIn.ModelRoutingEnabled). SetMcpXMLInject(groupIn.MCPXMLInject). SetAllowMessagesDispatch(groupIn.AllowMessagesDispatch). - SetRequireOauthOnly(groupIn.RequireOAuthOnly). - SetRequirePrivacySet(groupIn.RequirePrivacySet). SetDefaultMappedModel(groupIn.DefaultMappedModel) // 设置模型路由配置 @@ -122,8 +120,6 @@ func (r *groupRepository) Update(ctx context.Context, groupIn *service.Group) er SetModelRoutingEnabled(groupIn.ModelRoutingEnabled). SetMcpXMLInject(groupIn.MCPXMLInject). SetAllowMessagesDispatch(groupIn.AllowMessagesDispatch). - SetRequireOauthOnly(groupIn.RequireOAuthOnly). - SetRequirePrivacySet(groupIn.RequirePrivacySet). SetDefaultMappedModel(groupIn.DefaultMappedModel) // 显式处理可空字段:nil 需要 clear,非 nil 需要 set。 diff --git a/backend/internal/server/routes/admin.go b/backend/internal/server/routes/admin.go index 6829e93d..b921da95 100644 --- a/backend/internal/server/routes/admin.go +++ b/backend/internal/server/routes/admin.go @@ -407,15 +407,6 @@ func registerSettingsRoutes(admin *gin.RouterGroup, h *handler.Handlers) { // Beta 策略配置 adminSettings.GET("/beta-policy", h.Admin.Setting.GetBetaPolicySettings) adminSettings.PUT("/beta-policy", h.Admin.Setting.UpdateBetaPolicySettings) - // Sora S3 存储配置 - adminSettings.GET("/sora-s3", h.Admin.Setting.GetSoraS3Settings) - adminSettings.PUT("/sora-s3", h.Admin.Setting.UpdateSoraS3Settings) - adminSettings.POST("/sora-s3/test", h.Admin.Setting.TestSoraS3Connection) - adminSettings.GET("/sora-s3/profiles", h.Admin.Setting.ListSoraS3Profiles) - adminSettings.POST("/sora-s3/profiles", h.Admin.Setting.CreateSoraS3Profile) - adminSettings.PUT("/sora-s3/profiles/:profile_id", h.Admin.Setting.UpdateSoraS3Profile) - adminSettings.DELETE("/sora-s3/profiles/:profile_id", h.Admin.Setting.DeleteSoraS3Profile) - adminSettings.POST("/sora-s3/profiles/:profile_id/activate", h.Admin.Setting.SetActiveSoraS3Profile) } }