feat(channels): add "Available Channels" aggregate view
Add a read-only aggregate view per channel: its linked groups and a deterministic wildcard-free supported-model list with pricing details. Backend - service.Channel.SupportedModels(): combine ModelMapping keys with same-platform ModelPricing.Models; trailing "*" keys expand via pricing prefix match; platforms without a mapping produce no entries (intentional "no mapping = not shown" rule). - Extract splitWildcardSuffix() shared with toModelEntry. - Build a per-call pricing lookup map (platform+lowerName -> *pricing) to avoid O(N*M) scans in SupportedModels. - ChannelService.ListAvailable() aggregates channels + active groups; filters out group IDs no longer active. - Admin route GET /api/v1/admin/channels/available returns the full DTO (id, status, billing_model_source, restrict_models, groups, supported_models). - User route GET /api/v1/channels/available applies three filters: Status==active, visible-group intersection, and platform filter on supported_models (prevents cross-platform leak when a channel links to both a user-accessible group and an inaccessible one on another platform). Response is a plain array (matches the /groups/available sibling shape). Field whitelist omits billing_model_source, restrict_models, ids, status, sort_order. Frontend - New /admin/available-channels and /available-channels views backed by a shared AvailableChannelsTable component (admin adds status + billing-source columns via slots). - PricingRow extracted to its own SFC; SupportedModelChip references shared billing-mode constants in constants/channel.ts. - Sidebar: new entry above "渠道管理" for admin; matching entry in user nav. - i18n: zh + en coverage for both namespaces. Tests - SupportedModels: wildcard-only pricing skipped, prefix-matches- nothing, cross-platform bleed, case-insensitive dedup, empty platform mapping. - ListAvailable: nil groupRepo, inactive-group-ID dropped, stable case-insensitive name sort. - User handler: 401 on unauthenticated, visible-group intersection, platform filter on supported_models, JSON whitelist. - Admin handler: full DTO including default BillingModelSource fallback. Refs: issue #1729
This commit is contained in:
@@ -174,7 +174,8 @@ func initializeApplication(buildInfo handler.BuildInfo) (*Application, error) {
|
||||
claudeTokenProvider := service.ProvideClaudeTokenProvider(accountRepository, geminiTokenCache, oAuthService, oAuthRefreshAPI)
|
||||
digestSessionStore := service.NewDigestSessionStore()
|
||||
channelRepository := repository.NewChannelRepository(db)
|
||||
channelService := service.NewChannelService(channelRepository, apiKeyAuthCacheInvalidator)
|
||||
channelService := service.NewChannelService(channelRepository, groupRepository, apiKeyAuthCacheInvalidator)
|
||||
availableChannelHandler := admin.NewAvailableChannelHandler(channelService)
|
||||
modelPricingResolver := service.NewModelPricingResolver(channelService, billingService)
|
||||
balanceNotifyService := service.ProvideBalanceNotifyService(emailService, settingRepository, accountRepository)
|
||||
gatewayService := service.NewGatewayService(accountRepository, groupRepository, usageLogRepository, usageBillingRepository, userRepository, userSubscriptionRepository, userGroupRateRepository, gatewayCache, configConfig, schedulerSnapshotService, concurrencyService, billingService, rateLimitService, billingCacheService, identityService, httpUpstream, deferredService, claudeTokenProvider, sessionLimitCache, rpmCache, digestSessionStore, settingService, tlsFingerprintProfileService, channelService, modelPricingResolver, balanceNotifyService)
|
||||
@@ -234,7 +235,8 @@ func initializeApplication(buildInfo handler.BuildInfo) (*Application, error) {
|
||||
settingHandler := admin.NewSettingHandler(settingService, emailService, turnstileService, opsService, paymentConfigService, paymentService)
|
||||
paymentOrderExpiryService := service.ProvidePaymentOrderExpiryService(paymentService)
|
||||
paymentHandler := admin.NewPaymentHandler(paymentService, paymentConfigService)
|
||||
adminHandlers := handler.ProvideAdminHandlers(dashboardHandler, adminUserHandler, groupHandler, accountHandler, adminAnnouncementHandler, dataManagementHandler, backupHandler, oAuthHandler, openAIOAuthHandler, geminiOAuthHandler, antigravityOAuthHandler, proxyHandler, adminRedeemHandler, promoHandler, settingHandler, opsHandler, systemHandler, adminSubscriptionHandler, adminUsageHandler, userAttributeHandler, errorPassthroughHandler, tlsFingerprintProfileHandler, adminAPIKeyHandler, scheduledTestHandler, channelHandler, channelMonitorHandler, channelMonitorRequestTemplateHandler, paymentHandler)
|
||||
availableChannelUserHandler := handler.NewAvailableChannelHandler(channelService, apiKeyService)
|
||||
adminHandlers := handler.ProvideAdminHandlers(dashboardHandler, adminUserHandler, groupHandler, accountHandler, adminAnnouncementHandler, dataManagementHandler, backupHandler, oAuthHandler, openAIOAuthHandler, geminiOAuthHandler, antigravityOAuthHandler, proxyHandler, adminRedeemHandler, promoHandler, settingHandler, opsHandler, systemHandler, adminSubscriptionHandler, adminUsageHandler, userAttributeHandler, errorPassthroughHandler, tlsFingerprintProfileHandler, adminAPIKeyHandler, scheduledTestHandler, channelHandler, channelMonitorHandler, channelMonitorRequestTemplateHandler, availableChannelHandler, paymentHandler)
|
||||
usageRecordWorkerPool := service.NewUsageRecordWorkerPool(configConfig)
|
||||
userMsgQueueCache := repository.NewUserMsgQueueCache(redisClient)
|
||||
userMessageQueueService := service.ProvideUserMessageQueueService(userMsgQueueCache, rpmCache, configConfig)
|
||||
@@ -246,7 +248,7 @@ func initializeApplication(buildInfo handler.BuildInfo) (*Application, error) {
|
||||
paymentWebhookHandler := handler.NewPaymentWebhookHandler(paymentService, registry)
|
||||
idempotencyCoordinator := service.ProvideIdempotencyCoordinator(idempotencyRepository, configConfig)
|
||||
idempotencyCleanupService := service.ProvideIdempotencyCleanupService(idempotencyRepository, configConfig)
|
||||
handlers := handler.ProvideHandlers(authHandler, userHandler, apiKeyHandler, usageHandler, redeemHandler, subscriptionHandler, announcementHandler, channelMonitorUserHandler, adminHandlers, gatewayHandler, openAIGatewayHandler, handlerSettingHandler, totpHandler, handlerPaymentHandler, paymentWebhookHandler, idempotencyCoordinator, idempotencyCleanupService)
|
||||
handlers := handler.ProvideHandlers(authHandler, userHandler, apiKeyHandler, usageHandler, redeemHandler, subscriptionHandler, announcementHandler, channelMonitorUserHandler, adminHandlers, gatewayHandler, openAIGatewayHandler, handlerSettingHandler, totpHandler, handlerPaymentHandler, paymentWebhookHandler, availableChannelUserHandler, idempotencyCoordinator, idempotencyCleanupService)
|
||||
jwtAuthMiddleware := middleware.NewJWTAuthMiddleware(authService, userService)
|
||||
adminAuthMiddleware := middleware.NewAdminAuthMiddleware(authService, userService, settingService)
|
||||
apiKeyAuthMiddleware := middleware.NewAPIKeyAuthMiddleware(apiKeyService, subscriptionService, configConfig)
|
||||
|
||||
Reference in New Issue
Block a user