mirror of
https://github.com/fawney19/Aether.git
synced 2026-09-02 17:30:23 +08:00
fix: 修复 mypy 类型检查错误并升级到 Python 3.14
主要变更: - 修复 1483 个 mypy 类型检查错误 - 添加缺失的类型注解 (Any, Callable, Session 等) - 修复隐式 Optional 类型 (param: Type = None -> param: Type | None = None) - 修复 __new__ 单例模式返回类型 - 添加 type: ignore 注释处理第三方库类型问题 - 更新 pyproject.toml 依赖到 Python 3.14 兼容版本 - 更新 mypy/black 配置为 Python 3.14
This commit is contained in:
@@ -9,6 +9,9 @@
|
||||
- adaptive_mode 是计算字段,基于 rpm_limit 是否为 NULL
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
from dataclasses import dataclass
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, Query, Request
|
||||
@@ -21,6 +24,7 @@ from src.core.exceptions import InvalidRequestException, translate_pydantic_erro
|
||||
from src.database import get_db
|
||||
from src.models.database import ProviderAPIKey
|
||||
from src.services.rate_limit.adaptive_rpm import get_adaptive_rpm_manager
|
||||
from src.api.base.context import ApiRequestContext
|
||||
|
||||
router = APIRouter(prefix="/api/admin/adaptive", tags=["Adaptive RPM"])
|
||||
pipeline = ApiRequestPipeline()
|
||||
@@ -82,7 +86,7 @@ async def list_adaptive_keys(
|
||||
request: Request,
|
||||
provider_id: str | None = Query(None, description="按 Provider 过滤"),
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
) -> Any:
|
||||
"""
|
||||
获取所有启用自适应模式的Key列表
|
||||
|
||||
@@ -101,7 +105,7 @@ async def toggle_adaptive_mode(
|
||||
key_id: str,
|
||||
request: Request,
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
) -> Any:
|
||||
"""
|
||||
Toggle the RPM control mode for a specific key
|
||||
|
||||
@@ -122,7 +126,7 @@ async def get_adaptive_stats(
|
||||
key_id: str,
|
||||
request: Request,
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
) -> Any:
|
||||
"""
|
||||
获取指定Key的自适应 RPM 统计信息
|
||||
|
||||
@@ -144,7 +148,7 @@ async def reset_adaptive_learning(
|
||||
key_id: str,
|
||||
request: Request,
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
) -> Any:
|
||||
"""
|
||||
Reset the adaptive learning state for a specific key
|
||||
|
||||
@@ -169,7 +173,7 @@ async def set_rpm_limit(
|
||||
request: Request,
|
||||
limit: int = Query(..., ge=1, le=100, description="RPM limit value (1-100)"),
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
) -> Any:
|
||||
"""
|
||||
Set key to fixed RPM limit mode
|
||||
|
||||
@@ -188,7 +192,7 @@ async def set_rpm_limit(
|
||||
async def get_adaptive_summary(
|
||||
request: Request,
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
) -> Any:
|
||||
"""
|
||||
获取自适应 RPM 的全局统计摘要
|
||||
|
||||
@@ -208,7 +212,7 @@ async def get_adaptive_summary(
|
||||
class ListAdaptiveKeysAdapter(AdminApiAdapter):
|
||||
provider_id: str | None = None
|
||||
|
||||
async def handle(self, context): # type: ignore[override]
|
||||
async def handle(self, context: ApiRequestContext) -> Any: # type: ignore[override]
|
||||
# 自适应模式:rpm_limit = NULL
|
||||
query = context.db.query(ProviderAPIKey).filter(ProviderAPIKey.rpm_limit.is_(None))
|
||||
if self.provider_id:
|
||||
@@ -240,7 +244,7 @@ class ListAdaptiveKeysAdapter(AdminApiAdapter):
|
||||
class ToggleAdaptiveModeAdapter(AdminApiAdapter):
|
||||
key_id: str
|
||||
|
||||
async def handle(self, context): # type: ignore[override]
|
||||
async def handle(self, context: ApiRequestContext) -> Any: # type: ignore[override]
|
||||
key = context.db.query(ProviderAPIKey).filter(ProviderAPIKey.id == self.key_id).first()
|
||||
if not key:
|
||||
raise HTTPException(status_code=404, detail="Key not found")
|
||||
@@ -288,7 +292,7 @@ class ToggleAdaptiveModeAdapter(AdminApiAdapter):
|
||||
class GetAdaptiveStatsAdapter(AdminApiAdapter):
|
||||
key_id: str
|
||||
|
||||
async def handle(self, context): # type: ignore[override]
|
||||
async def handle(self, context: ApiRequestContext) -> Any: # type: ignore[override]
|
||||
key = context.db.query(ProviderAPIKey).filter(ProviderAPIKey.id == self.key_id).first()
|
||||
if not key:
|
||||
raise HTTPException(status_code=404, detail="Key not found")
|
||||
@@ -315,7 +319,7 @@ class GetAdaptiveStatsAdapter(AdminApiAdapter):
|
||||
class ResetAdaptiveLearningAdapter(AdminApiAdapter):
|
||||
key_id: str
|
||||
|
||||
async def handle(self, context): # type: ignore[override]
|
||||
async def handle(self, context: ApiRequestContext) -> Any: # type: ignore[override]
|
||||
key = context.db.query(ProviderAPIKey).filter(ProviderAPIKey.id == self.key_id).first()
|
||||
if not key:
|
||||
raise HTTPException(status_code=404, detail="Key not found")
|
||||
@@ -330,7 +334,7 @@ class SetRPMLimitAdapter(AdminApiAdapter):
|
||||
key_id: str
|
||||
limit: int
|
||||
|
||||
async def handle(self, context): # type: ignore[override]
|
||||
async def handle(self, context: ApiRequestContext) -> Any: # type: ignore[override]
|
||||
key = context.db.query(ProviderAPIKey).filter(ProviderAPIKey.id == self.key_id).first()
|
||||
if not key:
|
||||
raise HTTPException(status_code=404, detail="Key not found")
|
||||
@@ -350,7 +354,7 @@ class SetRPMLimitAdapter(AdminApiAdapter):
|
||||
|
||||
|
||||
class AdaptiveSummaryAdapter(AdminApiAdapter):
|
||||
async def handle(self, context): # type: ignore[override]
|
||||
async def handle(self, context: ApiRequestContext) -> Any: # type: ignore[override]
|
||||
# 自适应模式:rpm_limit = NULL
|
||||
adaptive_keys = (
|
||||
context.db.query(ProviderAPIKey).filter(ProviderAPIKey.rpm_limit.is_(None)).all()
|
||||
|
||||
@@ -3,6 +3,9 @@
|
||||
独立余额Key:不关联用户配额,有独立余额限制,用于给非注册用户使用。
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
import os
|
||||
from datetime import datetime, timedelta, timezone
|
||||
from zoneinfo import ZoneInfo
|
||||
@@ -18,6 +21,7 @@ from src.database import get_db
|
||||
from src.models.api import CreateApiKeyRequest
|
||||
from src.models.database import ApiKey
|
||||
from src.services.user.apikey import ApiKeyService
|
||||
from src.api.base.context import ApiRequestContext
|
||||
|
||||
|
||||
# 应用时区配置,默认为 Asia/Shanghai
|
||||
@@ -71,7 +75,7 @@ async def list_standalone_api_keys(
|
||||
limit: int = Query(100, ge=1, le=500),
|
||||
is_active: bool | None = None,
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
) -> Any:
|
||||
"""
|
||||
列出所有独立余额 API Keys
|
||||
|
||||
@@ -101,7 +105,7 @@ async def create_standalone_api_key(
|
||||
request: Request,
|
||||
key_data: CreateApiKeyRequest,
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
) -> Any:
|
||||
"""
|
||||
创建独立余额 API Key
|
||||
|
||||
@@ -138,7 +142,7 @@ async def create_standalone_api_key(
|
||||
@router.put("/{key_id}")
|
||||
async def update_api_key(
|
||||
key_id: str, request: Request, key_data: CreateApiKeyRequest, db: Session = Depends(get_db)
|
||||
):
|
||||
) -> Any:
|
||||
"""
|
||||
更新独立余额 API Key
|
||||
|
||||
@@ -174,7 +178,7 @@ async def update_api_key(
|
||||
|
||||
|
||||
@router.patch("/{key_id}")
|
||||
async def toggle_api_key(key_id: str, request: Request, db: Session = Depends(get_db)):
|
||||
async def toggle_api_key(key_id: str, request: Request, db: Session = Depends(get_db)) -> Any:
|
||||
"""
|
||||
切换 API Key 启用状态
|
||||
|
||||
@@ -193,7 +197,7 @@ async def toggle_api_key(key_id: str, request: Request, db: Session = Depends(ge
|
||||
|
||||
|
||||
@router.delete("/{key_id}")
|
||||
async def delete_api_key(key_id: str, request: Request, db: Session = Depends(get_db)):
|
||||
async def delete_api_key(key_id: str, request: Request, db: Session = Depends(get_db)) -> None:
|
||||
"""
|
||||
删除 API Key
|
||||
|
||||
@@ -210,7 +214,7 @@ async def delete_api_key(key_id: str, request: Request, db: Session = Depends(ge
|
||||
|
||||
|
||||
@router.patch("/{key_id}/lock")
|
||||
async def toggle_lock_api_key(key_id: str, request: Request, db: Session = Depends(get_db)):
|
||||
async def toggle_lock_api_key(key_id: str, request: Request, db: Session = Depends(get_db)) -> Any:
|
||||
"""
|
||||
切换 API Key 锁定状态
|
||||
|
||||
@@ -233,7 +237,7 @@ async def add_balance_to_key(
|
||||
key_id: str,
|
||||
request: Request,
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
) -> Any:
|
||||
"""
|
||||
调整独立余额 API Key 的余额
|
||||
|
||||
@@ -295,7 +299,7 @@ async def get_api_key_detail(
|
||||
request: Request,
|
||||
include_key: bool = Query(False, description="Include full decrypted key in response"),
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
) -> Any:
|
||||
"""
|
||||
获取 API Key 详情
|
||||
|
||||
@@ -335,7 +339,7 @@ class AdminListStandaloneKeysAdapter(AdminApiAdapter):
|
||||
self.limit = limit
|
||||
self.is_active = is_active
|
||||
|
||||
async def handle(self, context): # type: ignore[override]
|
||||
async def handle(self, context: ApiRequestContext) -> Any: # type: ignore[override]
|
||||
db = context.db
|
||||
# 只查询独立余额Keys
|
||||
query = db.query(ApiKey).filter(ApiKey.is_standalone == True)
|
||||
@@ -396,7 +400,7 @@ class AdminCreateStandaloneKeyAdapter(AdminApiAdapter):
|
||||
def __init__(self, key_data: CreateApiKeyRequest):
|
||||
self.key_data = key_data
|
||||
|
||||
async def handle(self, context): # type: ignore[override]
|
||||
async def handle(self, context: ApiRequestContext) -> Any: # type: ignore[override]
|
||||
db = context.db
|
||||
|
||||
# 独立Key必须设置初始余额
|
||||
@@ -458,7 +462,7 @@ class AdminUpdateApiKeyAdapter(AdminApiAdapter):
|
||||
self.key_id = key_id
|
||||
self.key_data = key_data
|
||||
|
||||
async def handle(self, context): # type: ignore[override]
|
||||
async def handle(self, context: ApiRequestContext) -> Any: # type: ignore[override]
|
||||
db = context.db
|
||||
api_key = db.query(ApiKey).filter(ApiKey.id == self.key_id).first()
|
||||
if not api_key:
|
||||
@@ -533,7 +537,7 @@ class AdminToggleApiKeyAdapter(AdminApiAdapter):
|
||||
def __init__(self, key_id: str):
|
||||
self.key_id = key_id
|
||||
|
||||
async def handle(self, context): # type: ignore[override]
|
||||
async def handle(self, context: ApiRequestContext) -> Any: # type: ignore[override]
|
||||
db = context.db
|
||||
api_key = db.query(ApiKey).filter(ApiKey.id == self.key_id).first()
|
||||
if not api_key:
|
||||
@@ -566,7 +570,7 @@ class AdminToggleLockApiKeyAdapter(AdminApiAdapter):
|
||||
def __init__(self, key_id: str):
|
||||
self.key_id = key_id
|
||||
|
||||
async def handle(self, context): # type: ignore[override]
|
||||
async def handle(self, context: ApiRequestContext) -> Any: # type: ignore[override]
|
||||
db = context.db
|
||||
api_key = db.query(ApiKey).filter(ApiKey.id == self.key_id).first()
|
||||
if not api_key:
|
||||
@@ -597,7 +601,7 @@ class AdminDeleteApiKeyAdapter(AdminApiAdapter):
|
||||
def __init__(self, key_id: str):
|
||||
self.key_id = key_id
|
||||
|
||||
async def handle(self, context): # type: ignore[override]
|
||||
async def handle(self, context: ApiRequestContext) -> Any: # type: ignore[override]
|
||||
db = context.db
|
||||
api_key = db.query(ApiKey).filter(ApiKey.id == self.key_id).first()
|
||||
if not api_key:
|
||||
@@ -625,7 +629,7 @@ class AdminAddBalanceAdapter(AdminApiAdapter):
|
||||
self.key_id = key_id
|
||||
self.amount_usd = amount_usd
|
||||
|
||||
async def handle(self, context): # type: ignore[override]
|
||||
async def handle(self, context: ApiRequestContext) -> Any: # type: ignore[override]
|
||||
db = context.db
|
||||
|
||||
# 使用 ApiKeyService 增加余额
|
||||
@@ -658,7 +662,7 @@ class AdminGetFullKeyAdapter(AdminApiAdapter):
|
||||
def __init__(self, key_id: str):
|
||||
self.key_id = key_id
|
||||
|
||||
async def handle(self, context): # type: ignore[override]
|
||||
async def handle(self, context: ApiRequestContext) -> Any: # type: ignore[override]
|
||||
from src.core.crypto import crypto_service
|
||||
|
||||
db = context.db
|
||||
@@ -697,7 +701,7 @@ class AdminGetKeyDetailAdapter(AdminApiAdapter):
|
||||
def __init__(self, key_id: str):
|
||||
self.key_id = key_id
|
||||
|
||||
async def handle(self, context): # type: ignore[override]
|
||||
async def handle(self, context: ApiRequestContext) -> Any: # type: ignore[override]
|
||||
db = context.db
|
||||
|
||||
api_key = db.query(ApiKey).filter(ApiKey.id == self.key_id).first()
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
Key RPM 限制管理 API
|
||||
"""
|
||||
|
||||
from typing import Any
|
||||
from dataclasses import dataclass
|
||||
|
||||
from fastapi import APIRouter, Depends, Request
|
||||
@@ -14,6 +15,7 @@ from src.database import get_db
|
||||
from src.models.database import ProviderAPIKey
|
||||
from src.models.endpoint_models import KeyRpmStatusResponse
|
||||
from src.services.rate_limit.concurrency_manager import get_concurrency_manager
|
||||
from src.api.base.context import ApiRequestContext
|
||||
|
||||
router = APIRouter(tags=["RPM Control"])
|
||||
pipeline = ApiRequestPipeline()
|
||||
@@ -71,7 +73,7 @@ async def reset_key_rpm(
|
||||
class AdminKeyRpmAdapter(AdminApiAdapter):
|
||||
key_id: str
|
||||
|
||||
async def handle(self, context): # type: ignore[override]
|
||||
async def handle(self, context: ApiRequestContext) -> Any: # type: ignore[override]
|
||||
db = context.db
|
||||
key = db.query(ProviderAPIKey).filter(ProviderAPIKey.id == self.key_id).first()
|
||||
if not key:
|
||||
@@ -91,7 +93,7 @@ class AdminKeyRpmAdapter(AdminApiAdapter):
|
||||
class AdminResetKeyRpmAdapter(AdminApiAdapter):
|
||||
key_id: str
|
||||
|
||||
async def handle(self, context): # type: ignore[override]
|
||||
async def handle(self, context: ApiRequestContext) -> Any: # type: ignore[override]
|
||||
concurrency_manager = await get_concurrency_manager()
|
||||
await concurrency_manager.reset_key_rpm(key_id=self.key_id)
|
||||
return {"message": "RPM 计数已重置"}
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
Endpoint 健康监控 API
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
from collections import defaultdict
|
||||
from dataclasses import dataclass
|
||||
from datetime import datetime, timedelta, timezone
|
||||
@@ -25,6 +28,7 @@ from src.models.endpoint_models import (
|
||||
)
|
||||
from src.services.health.endpoint import EndpointHealthService
|
||||
from src.services.health.monitor import health_monitor
|
||||
from src.api.base.context import ApiRequestContext
|
||||
|
||||
router = APIRouter(tags=["Endpoint Health"])
|
||||
pipeline = ApiRequestPipeline()
|
||||
@@ -58,7 +62,7 @@ async def get_endpoint_health_status(
|
||||
request: Request,
|
||||
lookback_hours: int = Query(6, ge=1, le=72, description="回溯的小时数"),
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
) -> Any:
|
||||
"""
|
||||
获取端点健康状态(简化视图,与用户端点统一)
|
||||
|
||||
@@ -218,7 +222,7 @@ async def recover_all_keys_health(
|
||||
|
||||
|
||||
class AdminHealthSummaryAdapter(AdminApiAdapter):
|
||||
async def handle(self, context): # type: ignore[override]
|
||||
async def handle(self, context: ApiRequestContext) -> Any: # type: ignore[override]
|
||||
summary = health_monitor.get_all_health_status(context.db)
|
||||
return HealthSummaryResponse(**summary)
|
||||
|
||||
@@ -229,7 +233,7 @@ class AdminEndpointHealthStatusAdapter(AdminApiAdapter):
|
||||
|
||||
lookback_hours: int
|
||||
|
||||
async def handle(self, context): # type: ignore[override]
|
||||
async def handle(self, context: ApiRequestContext) -> Any: # type: ignore[override]
|
||||
from src.services.health.endpoint import EndpointHealthService
|
||||
|
||||
db = context.db
|
||||
@@ -256,7 +260,7 @@ class AdminApiFormatHealthMonitorAdapter(AdminApiAdapter):
|
||||
lookback_hours: int
|
||||
per_format_limit: int
|
||||
|
||||
async def handle(self, context): # type: ignore[override]
|
||||
async def handle(self, context: ApiRequestContext) -> Any: # type: ignore[override]
|
||||
db = context.db
|
||||
now = datetime.now(timezone.utc)
|
||||
since = now - timedelta(hours=self.lookback_hours)
|
||||
@@ -463,7 +467,7 @@ class AdminKeyHealthAdapter(AdminApiAdapter):
|
||||
key_id: str
|
||||
api_format: str | None = None
|
||||
|
||||
async def handle(self, context): # type: ignore[override]
|
||||
async def handle(self, context: ApiRequestContext) -> Any: # type: ignore[override]
|
||||
health_data = health_monitor.get_key_health(context.db, self.key_id, self.api_format)
|
||||
if not health_data:
|
||||
raise NotFoundException(f"Key {self.key_id} 不存在")
|
||||
@@ -501,7 +505,7 @@ class AdminRecoverKeyHealthAdapter(AdminApiAdapter):
|
||||
key_id: str
|
||||
api_format: str | None = None
|
||||
|
||||
async def handle(self, context): # type: ignore[override]
|
||||
async def handle(self, context: ApiRequestContext) -> Any: # type: ignore[override]
|
||||
db = context.db
|
||||
key = db.query(ProviderAPIKey).filter(ProviderAPIKey.id == self.key_id).first()
|
||||
if not key:
|
||||
@@ -544,7 +548,7 @@ class AdminRecoverKeyHealthAdapter(AdminApiAdapter):
|
||||
class AdminRecoverAllKeysHealthAdapter(AdminApiAdapter):
|
||||
"""批量恢复所有熔断 Key 的健康状态"""
|
||||
|
||||
async def handle(self, context): # type: ignore[override]
|
||||
async def handle(self, context: ApiRequestContext) -> Any: # type: ignore[override]
|
||||
db = context.db
|
||||
|
||||
# 查找所有有熔断格式的 Key(检查 circuit_breaker_by_format JSON 字段)
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
Provider API Keys 管理
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
import json
|
||||
import uuid
|
||||
from dataclasses import dataclass
|
||||
@@ -25,6 +28,7 @@ from src.models.endpoint_models import (
|
||||
EndpointAPIKeyUpdate,
|
||||
)
|
||||
from src.services.cache.provider_cache import ProviderCacheService
|
||||
from src.api.base.context import ApiRequestContext
|
||||
|
||||
router = APIRouter(tags=["Provider Keys"])
|
||||
pipeline = ApiRequestPipeline()
|
||||
@@ -207,7 +211,7 @@ class AdminUpdateEndpointKeyAdapter(AdminApiAdapter):
|
||||
key_id: str
|
||||
key_data: EndpointAPIKeyUpdate
|
||||
|
||||
async def handle(self, context): # type: ignore[override]
|
||||
async def handle(self, context: ApiRequestContext) -> Any: # type: ignore[override]
|
||||
db = context.db
|
||||
key = db.query(ProviderAPIKey).filter(ProviderAPIKey.id == self.key_id).first()
|
||||
if not key:
|
||||
@@ -378,7 +382,7 @@ class AdminRevealEndpointKeyAdapter(AdminApiAdapter):
|
||||
|
||||
key_id: str
|
||||
|
||||
async def handle(self, context): # type: ignore[override]
|
||||
async def handle(self, context: ApiRequestContext) -> Any: # type: ignore[override]
|
||||
db = context.db
|
||||
key = db.query(ProviderAPIKey).filter(ProviderAPIKey.id == self.key_id).first()
|
||||
if not key:
|
||||
@@ -436,7 +440,7 @@ class AdminRevealEndpointKeyAdapter(AdminApiAdapter):
|
||||
class AdminDeleteEndpointKeyAdapter(AdminApiAdapter):
|
||||
key_id: str
|
||||
|
||||
async def handle(self, context): # type: ignore[override]
|
||||
async def handle(self, context: ApiRequestContext) -> Any: # type: ignore[override]
|
||||
db = context.db
|
||||
key = db.query(ProviderAPIKey).filter(ProviderAPIKey.id == self.key_id).first()
|
||||
if not key:
|
||||
@@ -472,7 +476,7 @@ class AdminDeleteEndpointKeyAdapter(AdminApiAdapter):
|
||||
|
||||
|
||||
class AdminGetKeysGroupedByFormatAdapter(AdminApiAdapter):
|
||||
async def handle(self, context): # type: ignore[override]
|
||||
async def handle(self, context: ApiRequestContext) -> Any: # type: ignore[override]
|
||||
db = context.db
|
||||
|
||||
# Key 属于 Provider:按 key.api_formats 分组展示
|
||||
@@ -677,7 +681,7 @@ class AdminListProviderKeysAdapter(AdminApiAdapter):
|
||||
skip: int
|
||||
limit: int
|
||||
|
||||
async def handle(self, context): # type: ignore[override]
|
||||
async def handle(self, context: ApiRequestContext) -> Any: # type: ignore[override]
|
||||
db = context.db
|
||||
provider = db.query(Provider).filter(Provider.id == self.provider_id).first()
|
||||
if not provider:
|
||||
@@ -702,7 +706,7 @@ class AdminCreateProviderKeyAdapter(AdminApiAdapter):
|
||||
provider_id: str
|
||||
key_data: EndpointAPIKeyCreate
|
||||
|
||||
async def handle(self, context): # type: ignore[override]
|
||||
async def handle(self, context: ApiRequestContext) -> Any: # type: ignore[override]
|
||||
db = context.db
|
||||
provider = db.query(Provider).filter(Provider.id == self.provider_id).first()
|
||||
if not provider:
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
ProviderEndpoint CRUD 管理 API
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
import uuid
|
||||
from dataclasses import dataclass
|
||||
from datetime import datetime, timezone
|
||||
@@ -18,6 +21,7 @@ from src.core.exceptions import InvalidRequestException, NotFoundException
|
||||
from src.core.logger import logger
|
||||
from src.database import get_db
|
||||
from src.models.database import Provider, ProviderAPIKey, ProviderEndpoint
|
||||
from src.api.base.context import ApiRequestContext
|
||||
from src.models.endpoint_models import (
|
||||
ProviderEndpointCreate,
|
||||
ProviderEndpointResponse,
|
||||
@@ -215,7 +219,7 @@ class AdminListProviderEndpointsAdapter(AdminApiAdapter):
|
||||
skip: int
|
||||
limit: int
|
||||
|
||||
async def handle(self, context): # type: ignore[override]
|
||||
async def handle(self, context: ApiRequestContext) -> Any: # type: ignore[override]
|
||||
db = context.db
|
||||
provider = db.query(Provider).filter(Provider.id == self.provider_id).first()
|
||||
if not provider:
|
||||
@@ -270,7 +274,7 @@ class AdminCreateProviderEndpointAdapter(AdminApiAdapter):
|
||||
provider_id: str
|
||||
endpoint_data: ProviderEndpointCreate
|
||||
|
||||
async def handle(self, context): # type: ignore[override]
|
||||
async def handle(self, context: ApiRequestContext) -> Any: # type: ignore[override]
|
||||
db = context.db
|
||||
provider = db.query(Provider).filter(Provider.id == self.provider_id).first()
|
||||
if not provider:
|
||||
@@ -340,7 +344,7 @@ class AdminCreateProviderEndpointAdapter(AdminApiAdapter):
|
||||
class AdminGetProviderEndpointAdapter(AdminApiAdapter):
|
||||
endpoint_id: str
|
||||
|
||||
async def handle(self, context): # type: ignore[override]
|
||||
async def handle(self, context: ApiRequestContext) -> Any: # type: ignore[override]
|
||||
db = context.db
|
||||
endpoint = (
|
||||
db.query(ProviderEndpoint, Provider)
|
||||
@@ -390,7 +394,7 @@ class AdminUpdateProviderEndpointAdapter(AdminApiAdapter):
|
||||
endpoint_id: str
|
||||
endpoint_data: ProviderEndpointUpdate
|
||||
|
||||
async def handle(self, context): # type: ignore[override]
|
||||
async def handle(self, context: ApiRequestContext) -> Any: # type: ignore[override]
|
||||
db = context.db
|
||||
endpoint = (
|
||||
db.query(ProviderEndpoint).filter(ProviderEndpoint.id == self.endpoint_id).first()
|
||||
@@ -459,7 +463,7 @@ class AdminUpdateProviderEndpointAdapter(AdminApiAdapter):
|
||||
class AdminDeleteProviderEndpointAdapter(AdminApiAdapter):
|
||||
endpoint_id: str
|
||||
|
||||
async def handle(self, context): # type: ignore[override]
|
||||
async def handle(self, context: ApiRequestContext) -> Any: # type: ignore[override]
|
||||
db = context.db
|
||||
endpoint = (
|
||||
db.query(ProviderEndpoint).filter(ProviderEndpoint.id == self.endpoint_id).first()
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
"""LDAP配置管理API端点。"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import re
|
||||
from typing import Any
|
||||
|
||||
@@ -15,6 +17,7 @@ from src.core.exceptions import InvalidRequestException, translate_pydantic_erro
|
||||
from src.core.logger import logger
|
||||
from src.database import get_db
|
||||
from src.models.database import AuditEventType, LDAPConfig, User, UserRole
|
||||
from src.api.base.context import ApiRequestContext
|
||||
from src.services.system.audit import AuditService
|
||||
|
||||
router = APIRouter(prefix="/api/admin/ldap", tags=["Admin - LDAP"])
|
||||
@@ -263,7 +266,7 @@ async def test_ldap_connection(request: Request, db: Session = Depends(get_db))
|
||||
|
||||
|
||||
class AdminGetLDAPConfigAdapter(AdminApiAdapter):
|
||||
async def handle(self, context) -> dict[str, Any]: # type: ignore[override]
|
||||
async def handle(self, context: ApiRequestContext) -> dict[str, Any]: # type: ignore[override]
|
||||
db = context.db
|
||||
config = db.query(LDAPConfig).first()
|
||||
|
||||
@@ -300,7 +303,7 @@ class AdminGetLDAPConfigAdapter(AdminApiAdapter):
|
||||
|
||||
|
||||
class AdminUpdateLDAPConfigAdapter(AdminApiAdapter):
|
||||
async def handle(self, context) -> dict[str, str]: # type: ignore[override]
|
||||
async def handle(self, context: ApiRequestContext) -> dict[str, str]: # type: ignore[override]
|
||||
db = context.db
|
||||
payload = context.ensure_json_body()
|
||||
|
||||
@@ -421,7 +424,7 @@ class AdminUpdateLDAPConfigAdapter(AdminApiAdapter):
|
||||
|
||||
|
||||
class AdminTestLDAPConnectionAdapter(AdminApiAdapter):
|
||||
async def handle(self, context) -> dict[str, Any]: # type: ignore[override]
|
||||
async def handle(self, context: ApiRequestContext) -> dict[str, Any]: # type: ignore[override]
|
||||
from src.services.auth.ldap import LDAPService
|
||||
|
||||
db = context.db
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
"""管理员 Management Token 管理端点"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
from dataclasses import dataclass
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, Query, Request
|
||||
@@ -50,7 +53,7 @@ async def list_all_management_tokens(
|
||||
skip: int = Query(0, ge=0),
|
||||
limit: int = Query(50, ge=1, le=100),
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
) -> Any:
|
||||
"""列出所有 Management Tokens(管理员)
|
||||
|
||||
管理员查看所有用户的 Management Tokens,支持筛选和分页。
|
||||
@@ -90,7 +93,7 @@ async def get_management_token(
|
||||
token_id: str,
|
||||
request: Request,
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
) -> Any:
|
||||
"""获取 Management Token 详情(管理员)
|
||||
|
||||
管理员查看任意 Management Token 的详细信息。
|
||||
@@ -119,7 +122,7 @@ async def get_management_token(
|
||||
@router.delete("/{token_id}")
|
||||
async def delete_management_token(
|
||||
token_id: str, request: Request, db: Session = Depends(get_db)
|
||||
):
|
||||
) -> Any:
|
||||
"""删除任意 Management Token(管理员)
|
||||
|
||||
管理员可以删除任意用户的 Management Token。
|
||||
@@ -137,7 +140,7 @@ async def delete_management_token(
|
||||
@router.patch("/{token_id}/status")
|
||||
async def toggle_management_token(
|
||||
token_id: str, request: Request, db: Session = Depends(get_db)
|
||||
):
|
||||
) -> Any:
|
||||
"""切换任意 Management Token 状态(管理员)
|
||||
|
||||
管理员可以启用/禁用任意用户的 Management Token。
|
||||
@@ -178,7 +181,7 @@ class AdminListManagementTokensAdapter(AdminManagementTokenApiAdapter):
|
||||
skip: int = 0
|
||||
limit: int = 50
|
||||
|
||||
async def handle(self, context: ApiRequestContext):
|
||||
async def handle(self, context: ApiRequestContext) -> Any:
|
||||
# 构建查询
|
||||
query = context.db.query(ManagementToken)
|
||||
|
||||
@@ -218,7 +221,7 @@ class AdminGetManagementTokenAdapter(AdminManagementTokenApiAdapter):
|
||||
name: str = "admin_get_management_token"
|
||||
token_id: str = ""
|
||||
|
||||
async def handle(self, context: ApiRequestContext):
|
||||
async def handle(self, context: ApiRequestContext) -> Any:
|
||||
token = ManagementTokenService.get_token_by_id(
|
||||
db=context.db, token_id=self.token_id
|
||||
)
|
||||
@@ -240,7 +243,7 @@ class AdminDeleteManagementTokenAdapter(AdminManagementTokenApiAdapter):
|
||||
token_id: str = ""
|
||||
audit_success_event = AuditEventType.MANAGEMENT_TOKEN_DELETED
|
||||
|
||||
async def handle(self, context: ApiRequestContext):
|
||||
async def handle(self, context: ApiRequestContext) -> Any:
|
||||
# 先获取 token 信息用于审计
|
||||
token = ManagementTokenService.get_token_by_id(
|
||||
db=context.db, token_id=self.token_id
|
||||
@@ -273,7 +276,7 @@ class AdminToggleManagementTokenAdapter(AdminManagementTokenApiAdapter):
|
||||
token_id: str = ""
|
||||
audit_success_event = AuditEventType.MANAGEMENT_TOKEN_UPDATED
|
||||
|
||||
async def handle(self, context: ApiRequestContext):
|
||||
async def handle(self, context: ApiRequestContext) -> Any:
|
||||
token = ManagementTokenService.toggle_status(
|
||||
db=context.db, token_id=self.token_id
|
||||
)
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
基于 GlobalModel 的聚合视图
|
||||
"""
|
||||
|
||||
from typing import Any
|
||||
from dataclasses import dataclass
|
||||
|
||||
from fastapi import APIRouter, Depends, Request
|
||||
@@ -13,6 +14,7 @@ from src.api.base.admin_adapter import AdminApiAdapter
|
||||
from src.api.base.pipeline import ApiRequestPipeline
|
||||
from src.database import get_db
|
||||
from src.models.database import GlobalModel, Model
|
||||
from src.api.base.context import ApiRequestContext
|
||||
from src.models.pydantic_models import (
|
||||
ModelCapabilities,
|
||||
ModelCatalogItem,
|
||||
@@ -59,7 +61,7 @@ class AdminGetModelCatalogAdapter(AdminApiAdapter):
|
||||
2. Model 表提供关联提供商和价格
|
||||
"""
|
||||
|
||||
async def handle(self, context): # type: ignore[override]
|
||||
async def handle(self, context: ApiRequestContext) -> Any: # type: ignore[override]
|
||||
db: Session = context.db
|
||||
|
||||
# 1. 获取所有活跃的 GlobalModel
|
||||
|
||||
@@ -4,9 +4,12 @@ GlobalModel Admin API
|
||||
提供 GlobalModel 的 CRUD 操作接口
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
from dataclasses import dataclass
|
||||
|
||||
from fastapi import APIRouter, Depends, Query, Request
|
||||
from fastapi import APIRouter, Depends, Query, Request, Response
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from src.api.base.admin_adapter import AdminApiAdapter
|
||||
@@ -26,6 +29,7 @@ from src.models.pydantic_models import (
|
||||
ModelCatalogProviderDetail,
|
||||
)
|
||||
from src.services.model.global_model import GlobalModelService
|
||||
from src.api.base.context import ApiRequestContext
|
||||
|
||||
router = APIRouter(prefix="/global", tags=["Admin - Global Models"])
|
||||
pipeline = ApiRequestPipeline()
|
||||
@@ -154,12 +158,12 @@ async def update_global_model(
|
||||
return await pipeline.run(adapter=adapter, http_request=request, db=db, mode=adapter.mode)
|
||||
|
||||
|
||||
@router.delete("/{global_model_id}", status_code=204)
|
||||
@router.delete("/{global_model_id}", status_code=204, response_class=Response)
|
||||
async def delete_global_model(
|
||||
request: Request,
|
||||
global_model_id: str,
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
) -> Response:
|
||||
"""
|
||||
删除 GlobalModel
|
||||
|
||||
@@ -174,7 +178,7 @@ async def delete_global_model(
|
||||
"""
|
||||
adapter = AdminDeleteGlobalModelAdapter(global_model_id=global_model_id)
|
||||
await pipeline.run(adapter=adapter, http_request=request, db=db, mode=adapter.mode)
|
||||
return None
|
||||
return Response(status_code=204)
|
||||
|
||||
|
||||
@router.post(
|
||||
@@ -256,7 +260,7 @@ class AdminListGlobalModelsAdapter(AdminApiAdapter):
|
||||
is_active: bool | None
|
||||
search: str | None
|
||||
|
||||
async def handle(self, context): # type: ignore[override]
|
||||
async def handle(self, context: ApiRequestContext) -> Any: # type: ignore[override]
|
||||
from sqlalchemy import func
|
||||
|
||||
from src.models.database import Model
|
||||
@@ -302,7 +306,7 @@ class AdminGetGlobalModelAdapter(AdminApiAdapter):
|
||||
|
||||
global_model_id: str
|
||||
|
||||
async def handle(self, context): # type: ignore[override]
|
||||
async def handle(self, context: ApiRequestContext) -> Any: # type: ignore[override]
|
||||
global_model = GlobalModelService.get_global_model(context.db, self.global_model_id)
|
||||
stats = GlobalModelService.get_global_model_stats(context.db, self.global_model_id)
|
||||
|
||||
@@ -320,7 +324,7 @@ class AdminCreateGlobalModelAdapter(AdminApiAdapter):
|
||||
|
||||
payload: GlobalModelCreate
|
||||
|
||||
async def handle(self, context): # type: ignore[override]
|
||||
async def handle(self, context: ApiRequestContext) -> Any: # type: ignore[override]
|
||||
from src.core.exceptions import InvalidRequestException
|
||||
from src.core.model_permissions import validate_and_extract_model_mappings
|
||||
|
||||
@@ -359,7 +363,7 @@ class AdminUpdateGlobalModelAdapter(AdminApiAdapter):
|
||||
global_model_id: str
|
||||
payload: GlobalModelUpdate
|
||||
|
||||
async def handle(self, context): # type: ignore[override]
|
||||
async def handle(self, context: ApiRequestContext) -> Any: # type: ignore[override]
|
||||
from src.core.exceptions import InvalidRequestException
|
||||
from src.core.model_permissions import validate_and_extract_model_mappings
|
||||
|
||||
@@ -418,7 +422,7 @@ class AdminDeleteGlobalModelAdapter(AdminApiAdapter):
|
||||
|
||||
global_model_id: str
|
||||
|
||||
async def handle(self, context): # type: ignore[override]
|
||||
async def handle(self, context: ApiRequestContext) -> Any: # type: ignore[override]
|
||||
# 使用行级锁获取 GlobalModel 信息,防止并发操作导致的竞态条件
|
||||
# 设置 2 秒锁超时,允许短暂等待而非立即失败
|
||||
from sqlalchemy import text
|
||||
@@ -467,7 +471,7 @@ class AdminBatchAssignToProvidersAdapter(AdminApiAdapter):
|
||||
global_model_id: str
|
||||
payload: BatchAssignToProvidersRequest
|
||||
|
||||
async def handle(self, context): # type: ignore[override]
|
||||
async def handle(self, context: ApiRequestContext) -> Any: # type: ignore[override]
|
||||
result = GlobalModelService.batch_assign_to_providers(
|
||||
db=context.db,
|
||||
global_model_id=self.global_model_id,
|
||||
@@ -492,7 +496,7 @@ class AdminGetGlobalModelProvidersAdapter(AdminApiAdapter):
|
||||
|
||||
global_model_id: str
|
||||
|
||||
async def handle(self, context): # type: ignore[override]
|
||||
async def handle(self, context: ApiRequestContext) -> Any: # type: ignore[override]
|
||||
from sqlalchemy.orm import joinedload
|
||||
|
||||
from src.models.database import Model
|
||||
|
||||
@@ -8,6 +8,8 @@ GlobalModel 请求链路预览 API
|
||||
- Key 的并发配置和健康状态
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass
|
||||
|
||||
from fastapi import APIRouter, Depends, Request
|
||||
@@ -30,6 +32,7 @@ from src.models.database import (
|
||||
ProviderEndpoint,
|
||||
)
|
||||
from src.services.cache.aware_scheduler import CacheAwareScheduler
|
||||
from src.api.base.context import ApiRequestContext
|
||||
from src.services.system.config import SystemConfigService
|
||||
|
||||
router = APIRouter(prefix="/global", tags=["Admin - Global Models"])
|
||||
@@ -204,7 +207,7 @@ class AdminGetModelRoutingPreviewAdapter(AdminApiAdapter):
|
||||
|
||||
global_model_id: str
|
||||
|
||||
async def handle(self, context) -> ModelRoutingPreviewResponse: # type: ignore[override]
|
||||
async def handle(self, context: ApiRequestContext) -> ModelRoutingPreviewResponse: # type: ignore[override]
|
||||
db = context.db
|
||||
|
||||
# 获取 GlobalModel
|
||||
|
||||
@@ -12,6 +12,7 @@ from src.api.base.admin_adapter import AdminApiAdapter
|
||||
from src.api.base.pipeline import ApiRequestPipeline
|
||||
from src.core.exceptions import InvalidRequestException, NotFoundException
|
||||
from src.core.modules import ModuleStatus, get_module_registry
|
||||
from src.api.base.context import ApiRequestContext
|
||||
from src.database import get_db
|
||||
|
||||
router = APIRouter(prefix="/api/admin/modules", tags=["Admin - Modules"])
|
||||
@@ -69,7 +70,7 @@ class SetModuleEnabledRequest(BaseModel):
|
||||
|
||||
|
||||
@router.get("/status")
|
||||
async def get_all_modules_status(request: Request, db: Session = Depends(get_db)):
|
||||
async def get_all_modules_status(request: Request, db: Session = Depends(get_db)) -> Any:
|
||||
"""
|
||||
获取所有模块状态
|
||||
|
||||
@@ -86,7 +87,7 @@ async def get_all_modules_status(request: Request, db: Session = Depends(get_db)
|
||||
@router.get("/status/{module_name}")
|
||||
async def get_module_status(
|
||||
module_name: str, request: Request, db: Session = Depends(get_db)
|
||||
):
|
||||
) -> Any:
|
||||
"""
|
||||
获取单个模块状态
|
||||
|
||||
@@ -105,7 +106,7 @@ async def get_module_status(
|
||||
@router.put("/status/{module_name}/enabled")
|
||||
async def set_module_enabled(
|
||||
module_name: str, request: Request, db: Session = Depends(get_db)
|
||||
):
|
||||
) -> Any:
|
||||
"""
|
||||
设置模块启用状态
|
||||
|
||||
@@ -131,7 +132,7 @@ async def set_module_enabled(
|
||||
class AdminGetAllModulesStatusAdapter(AdminApiAdapter):
|
||||
"""获取所有模块状态"""
|
||||
|
||||
async def handle(self, context) -> dict[str, Any]:
|
||||
async def handle(self, context: ApiRequestContext) -> dict[str, Any]:
|
||||
registry = get_module_registry()
|
||||
all_status = await registry.get_all_status_async(context.db)
|
||||
|
||||
@@ -147,7 +148,7 @@ class AdminGetModuleStatusAdapter(AdminApiAdapter):
|
||||
|
||||
module_name: str
|
||||
|
||||
async def handle(self, context) -> dict[str, Any]:
|
||||
async def handle(self, context: ApiRequestContext) -> dict[str, Any]:
|
||||
registry = get_module_registry()
|
||||
status = await registry.get_module_status_async(self.module_name, context.db)
|
||||
|
||||
@@ -163,7 +164,7 @@ class AdminSetModuleEnabledAdapter(AdminApiAdapter):
|
||||
|
||||
module_name: str
|
||||
|
||||
async def handle(self, context) -> dict[str, Any]:
|
||||
async def handle(self, context: ApiRequestContext) -> dict[str, Any]:
|
||||
registry = get_module_registry()
|
||||
|
||||
# 检查模块是否存在
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
"""管理员监控与审计端点。"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
from dataclasses import dataclass
|
||||
from datetime import datetime, timedelta, timezone
|
||||
|
||||
@@ -23,6 +26,7 @@ from src.models.database import User as DBUser
|
||||
from src.services.health.monitor import HealthMonitor
|
||||
from src.services.system.audit import audit_service
|
||||
from src.utils.database_helpers import escape_like_pattern
|
||||
from src.api.base.context import ApiRequestContext
|
||||
|
||||
|
||||
router = APIRouter(prefix="/api/admin/monitoring", tags=["Admin - Monitoring"])
|
||||
@@ -38,7 +42,7 @@ async def get_audit_logs(
|
||||
limit: int = Query(100, description="返回数量限制"),
|
||||
offset: int = Query(0, description="偏移量"),
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
) -> Any:
|
||||
"""
|
||||
获取审计日志
|
||||
|
||||
@@ -78,7 +82,7 @@ async def get_audit_logs(
|
||||
|
||||
|
||||
@router.get("/system-status")
|
||||
async def get_system_status(request: Request, db: Session = Depends(get_db)):
|
||||
async def get_system_status(request: Request, db: Session = Depends(get_db)) -> Any:
|
||||
"""
|
||||
获取系统状态
|
||||
|
||||
@@ -101,7 +105,7 @@ async def get_suspicious_activities(
|
||||
request: Request,
|
||||
hours: int = Query(24, description="时间范围(小时)"),
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
) -> Any:
|
||||
"""
|
||||
获取可疑活动记录
|
||||
|
||||
@@ -132,7 +136,7 @@ async def analyze_user_behavior(
|
||||
request: Request,
|
||||
days: int = Query(30, description="分析天数"),
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
) -> Any:
|
||||
"""
|
||||
分析用户行为
|
||||
|
||||
@@ -152,7 +156,7 @@ async def analyze_user_behavior(
|
||||
|
||||
|
||||
@router.get("/resilience-status")
|
||||
async def get_resilience_status(request: Request, db: Session = Depends(get_db)):
|
||||
async def get_resilience_status(request: Request, db: Session = Depends(get_db)) -> Any:
|
||||
"""
|
||||
获取韧性系统状态
|
||||
|
||||
@@ -171,7 +175,7 @@ async def get_resilience_status(request: Request, db: Session = Depends(get_db))
|
||||
|
||||
|
||||
@router.delete("/resilience/error-stats")
|
||||
async def reset_error_stats(request: Request, db: Session = Depends(get_db)):
|
||||
async def reset_error_stats(request: Request, db: Session = Depends(get_db)) -> None:
|
||||
"""
|
||||
重置错误统计
|
||||
|
||||
@@ -192,7 +196,7 @@ async def get_circuit_history(
|
||||
request: Request,
|
||||
limit: int = Query(50, ge=1, le=200),
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
) -> Any:
|
||||
"""
|
||||
获取熔断器历史记录
|
||||
|
||||
@@ -220,7 +224,7 @@ class AdminGetAuditLogsAdapter(AdminApiAdapter):
|
||||
# 查看审计日志本身不应该产生审计记录,避免刷新页面时产生大量无意义的日志
|
||||
audit_log_enabled: bool = False
|
||||
|
||||
async def handle(self, context): # type: ignore[override]
|
||||
async def handle(self, context: ApiRequestContext) -> Any: # type: ignore[override]
|
||||
db = context.db
|
||||
cutoff_time = datetime.now(timezone.utc) - timedelta(days=self.days)
|
||||
|
||||
@@ -284,7 +288,7 @@ class AdminGetAuditLogsAdapter(AdminApiAdapter):
|
||||
|
||||
|
||||
class AdminSystemStatusAdapter(AdminApiAdapter):
|
||||
async def handle(self, context): # type: ignore[override]
|
||||
async def handle(self, context: ApiRequestContext) -> Any: # type: ignore[override]
|
||||
db = context.db
|
||||
|
||||
total_users = db.query(func.count(DBUser.id)).scalar()
|
||||
@@ -361,7 +365,7 @@ class AdminSystemStatusAdapter(AdminApiAdapter):
|
||||
class AdminSuspiciousActivitiesAdapter(AdminApiAdapter):
|
||||
hours: int
|
||||
|
||||
async def handle(self, context): # type: ignore[override]
|
||||
async def handle(self, context: ApiRequestContext) -> Any: # type: ignore[override]
|
||||
db = context.db
|
||||
activities = audit_service.get_suspicious_activities(db=db, hours=self.hours, limit=100)
|
||||
response = {
|
||||
@@ -393,7 +397,7 @@ class AdminUserBehaviorAdapter(AdminApiAdapter):
|
||||
user_id: str
|
||||
days: int
|
||||
|
||||
async def handle(self, context): # type: ignore[override]
|
||||
async def handle(self, context: ApiRequestContext) -> Any: # type: ignore[override]
|
||||
result = audit_service.analyze_user_behavior(
|
||||
db=context.db,
|
||||
user_id=self.user_id,
|
||||
@@ -409,7 +413,7 @@ class AdminUserBehaviorAdapter(AdminApiAdapter):
|
||||
|
||||
|
||||
class AdminResilienceStatusAdapter(AdminApiAdapter):
|
||||
async def handle(self, context): # type: ignore[override]
|
||||
async def handle(self, context: ApiRequestContext) -> Any: # type: ignore[override]
|
||||
try:
|
||||
from src.core.resilience import resilience_manager
|
||||
except ImportError as exc:
|
||||
@@ -454,7 +458,7 @@ class AdminResilienceStatusAdapter(AdminApiAdapter):
|
||||
|
||||
|
||||
class AdminResetErrorStatsAdapter(AdminApiAdapter):
|
||||
async def handle(self, context): # type: ignore[override]
|
||||
async def handle(self, context: ApiRequestContext) -> Any: # type: ignore[override]
|
||||
try:
|
||||
from src.core.resilience import resilience_manager
|
||||
except ImportError as exc:
|
||||
@@ -486,7 +490,7 @@ class AdminCircuitHistoryAdapter(AdminApiAdapter):
|
||||
super().__init__()
|
||||
self.limit = limit
|
||||
|
||||
async def handle(self, context): # type: ignore[override]
|
||||
async def handle(self, context: ApiRequestContext) -> Any: # type: ignore[override]
|
||||
history = HealthMonitor.get_circuit_history(self.limit)
|
||||
context.add_audit_metadata(
|
||||
action="circuit_history",
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
提供缓存亲和性统计、管理和监控功能
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass
|
||||
from typing import Any
|
||||
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
请求链路追踪 API 端点
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
from dataclasses import dataclass
|
||||
from datetime import datetime
|
||||
|
||||
@@ -15,6 +18,7 @@ from src.database import get_db
|
||||
from src.models.database import Provider, ProviderEndpoint, ProviderAPIKey
|
||||
from src.core.crypto import crypto_service
|
||||
from src.services.request.candidate import RequestCandidateService
|
||||
from src.api.base.context import ApiRequestContext
|
||||
|
||||
router = APIRouter(prefix="/api/admin/monitoring/trace", tags=["Admin - Monitoring: Trace"])
|
||||
pipeline = ApiRequestPipeline()
|
||||
@@ -69,7 +73,7 @@ async def get_request_trace(
|
||||
request_id: str,
|
||||
request: Request,
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
) -> Any:
|
||||
"""
|
||||
获取请求的完整追踪信息
|
||||
|
||||
@@ -122,7 +126,7 @@ async def get_provider_failure_rate(
|
||||
request: Request,
|
||||
limit: int = Query(100, ge=1, le=1000, description="统计最近的尝试数量"),
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
) -> Any:
|
||||
"""
|
||||
获取提供商的失败率统计
|
||||
|
||||
@@ -153,7 +157,7 @@ async def get_provider_failure_rate(
|
||||
class AdminGetRequestTraceAdapter(AdminApiAdapter):
|
||||
request_id: str
|
||||
|
||||
async def handle(self, context): # type: ignore[override]
|
||||
async def handle(self, context: ApiRequestContext) -> Any: # type: ignore[override]
|
||||
db = context.db
|
||||
|
||||
# 只查询 candidates
|
||||
@@ -326,7 +330,7 @@ class AdminProviderFailureRateAdapter(AdminApiAdapter):
|
||||
provider_id: str
|
||||
limit: int
|
||||
|
||||
async def handle(self, context): # type: ignore[override]
|
||||
async def handle(self, context: ApiRequestContext) -> Any: # type: ignore[override]
|
||||
result = RequestCandidateService.get_candidate_stats_by_provider(
|
||||
db=context.db,
|
||||
provider_id=self.provider_id,
|
||||
|
||||
@@ -8,6 +8,8 @@ Provider 操作 API 路由
|
||||
- 配置管理
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import asdict, is_dataclass
|
||||
from typing import Any
|
||||
|
||||
@@ -146,14 +148,14 @@ def _serialize_data(data: Any) -> Any:
|
||||
|
||||
|
||||
@router.get("/architectures", response_model=list[ArchitectureInfo])
|
||||
async def list_architectures(_: User = Depends(require_admin)):
|
||||
async def list_architectures(_: User = Depends(require_admin)) -> Any:
|
||||
"""获取所有可用的架构"""
|
||||
registry = get_registry()
|
||||
return registry.to_dict_list()
|
||||
|
||||
|
||||
@router.get("/architectures/{architecture_id}", response_model=ArchitectureInfo)
|
||||
async def get_architecture(architecture_id: str, _: User = Depends(require_admin)):
|
||||
async def get_architecture(architecture_id: str, _: User = Depends(require_admin)) -> Any:
|
||||
"""获取指定架构的详情"""
|
||||
registry = get_registry()
|
||||
arch = registry.get(architecture_id)
|
||||
@@ -167,7 +169,7 @@ async def get_provider_ops_status(
|
||||
provider_id: str,
|
||||
db: Session = Depends(get_db),
|
||||
_: User = Depends(require_admin),
|
||||
):
|
||||
) -> Any:
|
||||
"""获取 Provider 的操作状态"""
|
||||
service = ProviderOpsService(db)
|
||||
|
||||
@@ -200,7 +202,7 @@ async def get_provider_ops_config(
|
||||
provider_id: str,
|
||||
db: Session = Depends(get_db),
|
||||
_: User = Depends(require_admin),
|
||||
):
|
||||
) -> Any:
|
||||
"""
|
||||
获取 Provider 的操作配置(脱敏)
|
||||
|
||||
@@ -251,7 +253,7 @@ async def save_provider_ops_config(
|
||||
request: SaveConfigRequest,
|
||||
db: Session = Depends(get_db),
|
||||
_: User = Depends(require_admin),
|
||||
):
|
||||
) -> Any:
|
||||
"""保存 Provider 的操作配置"""
|
||||
service = ProviderOpsService(db)
|
||||
|
||||
@@ -287,7 +289,7 @@ async def verify_provider_auth(
|
||||
request: SaveConfigRequest,
|
||||
db: Session = Depends(get_db),
|
||||
_: User = Depends(require_admin),
|
||||
):
|
||||
) -> Any:
|
||||
"""
|
||||
验证 Provider 认证配置
|
||||
|
||||
@@ -343,7 +345,7 @@ async def delete_provider_ops_config(
|
||||
provider_id: str,
|
||||
db: Session = Depends(get_db),
|
||||
_: User = Depends(require_admin),
|
||||
):
|
||||
) -> Any:
|
||||
"""删除 Provider 的操作配置"""
|
||||
service = ProviderOpsService(db)
|
||||
success = service.delete_config(provider_id)
|
||||
@@ -360,7 +362,7 @@ async def connect_provider(
|
||||
request: ConnectRequest,
|
||||
db: Session = Depends(get_db),
|
||||
_: User = Depends(require_admin),
|
||||
):
|
||||
) -> Any:
|
||||
"""建立与 Provider 的连接"""
|
||||
service = ProviderOpsService(db)
|
||||
|
||||
@@ -377,7 +379,7 @@ async def disconnect_provider(
|
||||
provider_id: str,
|
||||
db: Session = Depends(get_db),
|
||||
_: User = Depends(require_admin),
|
||||
):
|
||||
) -> Any:
|
||||
"""断开与 Provider 的连接"""
|
||||
service = ProviderOpsService(db)
|
||||
await service.disconnect(provider_id)
|
||||
@@ -395,7 +397,7 @@ async def execute_action(
|
||||
request: ExecuteActionRequest,
|
||||
db: Session = Depends(get_db),
|
||||
_: User = Depends(require_admin),
|
||||
):
|
||||
) -> Any:
|
||||
"""执行指定操作"""
|
||||
service = ProviderOpsService(db)
|
||||
|
||||
@@ -423,7 +425,7 @@ async def get_balance(
|
||||
refresh: bool = True,
|
||||
db: Session = Depends(get_db),
|
||||
_: User = Depends(require_admin),
|
||||
):
|
||||
) -> Any:
|
||||
"""
|
||||
获取余额(优先返回缓存,后台异步刷新)
|
||||
|
||||
@@ -449,7 +451,7 @@ async def refresh_balance(
|
||||
provider_id: str,
|
||||
db: Session = Depends(get_db),
|
||||
_: User = Depends(require_admin),
|
||||
):
|
||||
) -> Any:
|
||||
"""立即刷新余额(同步等待结果)"""
|
||||
service = ProviderOpsService(db)
|
||||
result = await service.query_balance(provider_id)
|
||||
@@ -470,7 +472,7 @@ async def checkin(
|
||||
provider_id: str,
|
||||
db: Session = Depends(get_db),
|
||||
_: User = Depends(require_admin),
|
||||
):
|
||||
) -> Any:
|
||||
"""签到(快捷方法)"""
|
||||
service = ProviderOpsService(db)
|
||||
result = await service.checkin(provider_id)
|
||||
@@ -491,7 +493,7 @@ async def batch_query_balance(
|
||||
provider_ids: list[str] | None = None,
|
||||
db: Session = Depends(get_db),
|
||||
_: User = Depends(require_admin),
|
||||
):
|
||||
) -> Any:
|
||||
"""批量查询余额"""
|
||||
service = ProviderOpsService(db)
|
||||
results = await service.batch_query_balance(provider_ids)
|
||||
|
||||
@@ -3,6 +3,9 @@ Provider Query API 端点
|
||||
用于查询提供商的模型列表等信息
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
import asyncio
|
||||
|
||||
import httpx
|
||||
@@ -63,7 +66,7 @@ async def query_available_models(
|
||||
request: ModelsQueryRequest,
|
||||
db: Session = Depends(get_db),
|
||||
current_user: User = Depends(get_current_user),
|
||||
):
|
||||
) -> Any:
|
||||
"""
|
||||
查询提供商可用模型
|
||||
|
||||
@@ -118,7 +121,7 @@ async def query_available_models(
|
||||
raise HTTPException(status_code=400, detail="No active API Key found for this provider")
|
||||
|
||||
# 并发获取所有 Key 的模型
|
||||
async def fetch_for_key(api_key):
|
||||
async def fetch_for_key(api_key: Any) -> Any:
|
||||
# 非强制刷新时,先检查缓存
|
||||
if not request.force_refresh:
|
||||
cached_models = await get_upstream_models_from_cache(
|
||||
@@ -246,7 +249,7 @@ async def _fetch_models_for_single_key(
|
||||
api_key_id: str,
|
||||
format_to_endpoint: dict[str, ProviderEndpoint],
|
||||
force_refresh: bool,
|
||||
):
|
||||
) -> Any:
|
||||
"""获取单个 Key 的模型列表"""
|
||||
# 查找指定的 Key
|
||||
api_key = next(
|
||||
@@ -305,7 +308,7 @@ async def test_model(
|
||||
request: TestModelRequest,
|
||||
db: Session = Depends(get_db),
|
||||
current_user: User = Depends(get_current_user),
|
||||
):
|
||||
) -> Any:
|
||||
"""
|
||||
测试模型连接性
|
||||
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
提供商策略管理 API 端点
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
from datetime import datetime, timedelta, timezone
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, Request
|
||||
@@ -16,6 +19,7 @@ from src.core.exceptions import InvalidRequestException, translate_pydantic_erro
|
||||
from src.core.logger import logger
|
||||
from src.database import get_db
|
||||
from src.models.database import Provider
|
||||
from src.api.base.context import ApiRequestContext
|
||||
from src.models.database_extensions import ProviderUsageTracking
|
||||
|
||||
router = APIRouter(prefix="/api/admin/provider-strategy", tags=["Provider Strategy"])
|
||||
@@ -37,7 +41,7 @@ async def update_provider_billing(
|
||||
provider_id: str,
|
||||
request: Request,
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
) -> Any:
|
||||
"""
|
||||
更新提供商计费配置
|
||||
|
||||
@@ -73,7 +77,7 @@ async def get_provider_stats(
|
||||
request: Request,
|
||||
hours: int = 24,
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
) -> Any:
|
||||
"""
|
||||
获取提供商统计数据
|
||||
|
||||
@@ -112,14 +116,14 @@ async def reset_provider_quota(
|
||||
provider_id: str,
|
||||
request: Request,
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
) -> Any:
|
||||
"""Reset provider quota usage to zero"""
|
||||
adapter = AdminProviderResetQuotaAdapter(provider_id=provider_id)
|
||||
return await pipeline.run(adapter=adapter, http_request=request, db=db, mode=adapter.mode)
|
||||
|
||||
|
||||
@router.get("/strategies")
|
||||
async def list_available_strategies(request: Request, db: Session = Depends(get_db)):
|
||||
async def list_available_strategies(request: Request, db: Session = Depends(get_db)) -> Any:
|
||||
"""
|
||||
获取可用负载均衡策略列表
|
||||
|
||||
@@ -142,7 +146,7 @@ class AdminProviderBillingAdapter(AdminApiAdapter):
|
||||
def __init__(self, provider_id: str):
|
||||
self.provider_id = provider_id
|
||||
|
||||
async def handle(self, context):
|
||||
async def handle(self, context: ApiRequestContext) -> Any:
|
||||
db = context.db
|
||||
payload = context.ensure_json_body()
|
||||
try:
|
||||
@@ -215,7 +219,7 @@ class AdminProviderStatsAdapter(AdminApiAdapter):
|
||||
self.provider_id = provider_id
|
||||
self.hours = hours
|
||||
|
||||
async def handle(self, context):
|
||||
async def handle(self, context: ApiRequestContext) -> Any:
|
||||
db = context.db
|
||||
provider = db.query(Provider).filter(Provider.id == self.provider_id).first()
|
||||
if not provider:
|
||||
@@ -271,7 +275,7 @@ class AdminProviderResetQuotaAdapter(AdminApiAdapter):
|
||||
def __init__(self, provider_id: str):
|
||||
self.provider_id = provider_id
|
||||
|
||||
async def handle(self, context):
|
||||
async def handle(self, context: ApiRequestContext) -> Any:
|
||||
db = context.db
|
||||
provider = db.query(Provider).filter(Provider.id == self.provider_id).first()
|
||||
if not provider:
|
||||
@@ -297,7 +301,7 @@ class AdminProviderResetQuotaAdapter(AdminApiAdapter):
|
||||
|
||||
|
||||
class AdminListStrategiesAdapter(AdminApiAdapter):
|
||||
async def handle(self, context):
|
||||
async def handle(self, context: ApiRequestContext) -> Any:
|
||||
from src.plugins.manager import get_plugin_manager
|
||||
|
||||
plugin_manager = get_plugin_manager()
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
Provider 模型管理 API
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass
|
||||
from typing import Any
|
||||
|
||||
@@ -35,6 +37,7 @@ from src.models.database import (
|
||||
Provider,
|
||||
)
|
||||
from src.services.model.service import ModelService
|
||||
from src.api.base.context import ApiRequestContext
|
||||
|
||||
router = APIRouter(tags=["Model Management"])
|
||||
pipeline = ApiRequestPipeline()
|
||||
@@ -205,7 +208,7 @@ async def delete_provider_model(
|
||||
model_id: str,
|
||||
request: Request,
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
) -> Any:
|
||||
"""
|
||||
删除模型
|
||||
|
||||
@@ -264,7 +267,7 @@ async def get_provider_available_source_models(
|
||||
provider_id: str,
|
||||
request: Request,
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
) -> Any:
|
||||
"""
|
||||
获取提供商支持的可用源模型
|
||||
|
||||
@@ -379,7 +382,7 @@ class AdminListProviderModelsAdapter(AdminApiAdapter):
|
||||
skip: int
|
||||
limit: int
|
||||
|
||||
async def handle(self, context): # type: ignore[override]
|
||||
async def handle(self, context: ApiRequestContext) -> Any: # type: ignore[override]
|
||||
db = context.db
|
||||
provider = db.query(Provider).filter(Provider.id == self.provider_id).first()
|
||||
if not provider:
|
||||
@@ -396,7 +399,7 @@ class AdminCreateProviderModelAdapter(AdminApiAdapter):
|
||||
provider_id: str
|
||||
model_data: ModelCreate
|
||||
|
||||
async def handle(self, context): # type: ignore[override]
|
||||
async def handle(self, context: ApiRequestContext) -> Any: # type: ignore[override]
|
||||
db = context.db
|
||||
provider = db.query(Provider).filter(Provider.id == self.provider_id).first()
|
||||
if not provider:
|
||||
@@ -416,7 +419,7 @@ class AdminGetProviderModelAdapter(AdminApiAdapter):
|
||||
provider_id: str
|
||||
model_id: str
|
||||
|
||||
async def handle(self, context): # type: ignore[override]
|
||||
async def handle(self, context: ApiRequestContext) -> Any: # type: ignore[override]
|
||||
db = context.db
|
||||
model = (
|
||||
db.query(Model)
|
||||
@@ -435,7 +438,7 @@ class AdminUpdateProviderModelAdapter(AdminApiAdapter):
|
||||
model_id: str
|
||||
model_data: ModelUpdate
|
||||
|
||||
async def handle(self, context): # type: ignore[override]
|
||||
async def handle(self, context: ApiRequestContext) -> Any: # type: ignore[override]
|
||||
db = context.db
|
||||
model = (
|
||||
db.query(Model)
|
||||
@@ -459,7 +462,7 @@ class AdminDeleteProviderModelAdapter(AdminApiAdapter):
|
||||
provider_id: str
|
||||
model_id: str
|
||||
|
||||
async def handle(self, context): # type: ignore[override]
|
||||
async def handle(self, context: ApiRequestContext) -> Any: # type: ignore[override]
|
||||
db = context.db
|
||||
model = (
|
||||
db.query(Model)
|
||||
@@ -484,7 +487,7 @@ class AdminBatchCreateModelsAdapter(AdminApiAdapter):
|
||||
provider_id: str
|
||||
models_data: list[ModelCreate]
|
||||
|
||||
async def handle(self, context): # type: ignore[override]
|
||||
async def handle(self, context: ApiRequestContext) -> Any: # type: ignore[override]
|
||||
db = context.db
|
||||
provider = db.query(Provider).filter(Provider.id == self.provider_id).first()
|
||||
if not provider:
|
||||
@@ -503,7 +506,7 @@ class AdminBatchCreateModelsAdapter(AdminApiAdapter):
|
||||
class AdminGetProviderAvailableSourceModelsAdapter(AdminApiAdapter):
|
||||
provider_id: str
|
||||
|
||||
async def handle(self, context): # type: ignore[override]
|
||||
async def handle(self, context: ApiRequestContext) -> Any: # type: ignore[override]
|
||||
"""
|
||||
返回 Provider 支持的所有 GlobalModel
|
||||
|
||||
@@ -571,7 +574,7 @@ class AdminBatchAssignModelsToProviderAdapter(AdminApiAdapter):
|
||||
provider_id: str
|
||||
payload: BatchAssignModelsToProviderRequest
|
||||
|
||||
async def handle(self, context): # type: ignore[override]
|
||||
async def handle(self, context: ApiRequestContext) -> Any: # type: ignore[override]
|
||||
db = context.db
|
||||
provider = db.query(Provider).filter(Provider.id == self.provider_id).first()
|
||||
if not provider:
|
||||
@@ -654,7 +657,7 @@ class AdminImportFromUpstreamAdapter(AdminApiAdapter):
|
||||
provider_id: str
|
||||
payload: ImportFromUpstreamRequest
|
||||
|
||||
async def handle(self, context): # type: ignore[override]
|
||||
async def handle(self, context: ApiRequestContext) -> Any: # type: ignore[override]
|
||||
db = context.db
|
||||
provider = db.query(Provider).filter(Provider.id == self.provider_id).first()
|
||||
if not provider:
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
"""管理员 Provider 管理路由。"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
import asyncio
|
||||
from datetime import datetime, timezone
|
||||
|
||||
@@ -19,6 +22,7 @@ from src.database import get_db
|
||||
from src.models.admin_requests import CreateProviderRequest, UpdateProviderRequest
|
||||
from src.models.database import GlobalModel, Provider, ProviderAPIKey
|
||||
from src.services.cache.provider_cache import ProviderCacheService
|
||||
from src.api.base.context import ApiRequestContext
|
||||
|
||||
router = APIRouter(tags=["Provider CRUD"])
|
||||
pipeline = ApiRequestPipeline()
|
||||
@@ -96,7 +100,7 @@ async def list_providers(
|
||||
limit: int = Query(100, ge=1, le=500),
|
||||
is_active: bool | None = None,
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
) -> Any:
|
||||
"""
|
||||
获取提供商列表
|
||||
|
||||
@@ -123,7 +127,7 @@ async def list_providers(
|
||||
|
||||
|
||||
@router.post("/")
|
||||
async def create_provider(request: Request, db: Session = Depends(get_db)):
|
||||
async def create_provider(request: Request, db: Session = Depends(get_db)) -> Any:
|
||||
"""
|
||||
创建新提供商
|
||||
|
||||
@@ -155,7 +159,7 @@ async def create_provider(request: Request, db: Session = Depends(get_db)):
|
||||
|
||||
|
||||
@router.put("/{provider_id}")
|
||||
async def update_provider(provider_id: str, request: Request, db: Session = Depends(get_db)):
|
||||
async def update_provider(provider_id: str, request: Request, db: Session = Depends(get_db)) -> None:
|
||||
"""
|
||||
更新提供商配置
|
||||
|
||||
@@ -191,7 +195,7 @@ async def update_provider(provider_id: str, request: Request, db: Session = Depe
|
||||
|
||||
|
||||
@router.delete("/{provider_id}")
|
||||
async def delete_provider(provider_id: str, request: Request, db: Session = Depends(get_db)):
|
||||
async def delete_provider(provider_id: str, request: Request, db: Session = Depends(get_db)) -> None:
|
||||
"""
|
||||
删除提供商
|
||||
|
||||
@@ -213,7 +217,7 @@ class AdminListProvidersAdapter(AdminApiAdapter):
|
||||
self.limit = limit
|
||||
self.is_active = is_active
|
||||
|
||||
async def handle(self, context): # type: ignore[override]
|
||||
async def handle(self, context: ApiRequestContext) -> Any: # type: ignore[override]
|
||||
db = context.db
|
||||
query = db.query(Provider)
|
||||
if self.is_active is not None:
|
||||
@@ -251,7 +255,7 @@ class AdminListProvidersAdapter(AdminApiAdapter):
|
||||
|
||||
|
||||
class AdminCreateProviderAdapter(AdminApiAdapter):
|
||||
async def handle(self, context): # type: ignore[override]
|
||||
async def handle(self, context: ApiRequestContext) -> Any: # type: ignore[override]
|
||||
db = context.db
|
||||
payload = context.ensure_json_body()
|
||||
|
||||
@@ -333,7 +337,7 @@ class AdminUpdateProviderAdapter(AdminApiAdapter):
|
||||
def __init__(self, provider_id: str):
|
||||
self.provider_id = provider_id
|
||||
|
||||
async def handle(self, context): # type: ignore[override]
|
||||
async def handle(self, context: ApiRequestContext) -> Any: # type: ignore[override]
|
||||
db = context.db
|
||||
payload = context.ensure_json_body()
|
||||
|
||||
@@ -412,7 +416,7 @@ class AdminDeleteProviderAdapter(AdminApiAdapter):
|
||||
def __init__(self, provider_id: str):
|
||||
self.provider_id = provider_id
|
||||
|
||||
async def handle(self, context): # type: ignore[override]
|
||||
async def handle(self, context: ApiRequestContext) -> Any: # type: ignore[override]
|
||||
db = context.db
|
||||
provider = db.query(Provider).filter(Provider.id == self.provider_id).first()
|
||||
if not provider:
|
||||
@@ -483,7 +487,7 @@ class AdminGetProviderMappingPreviewAdapter(AdminApiAdapter):
|
||||
def __init__(self, provider_id: str):
|
||||
self.provider_id = provider_id
|
||||
|
||||
async def handle(self, context) -> ProviderMappingPreviewResponse: # type: ignore[override]
|
||||
async def handle(self, context: ApiRequestContext) -> ProviderMappingPreviewResponse: # type: ignore[override]
|
||||
db = context.db
|
||||
|
||||
# 获取 Provider
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
Provider 摘要与健康监控 API
|
||||
"""
|
||||
|
||||
from typing import Any
|
||||
from dataclasses import dataclass
|
||||
from datetime import datetime, timedelta, timezone
|
||||
|
||||
@@ -22,6 +23,7 @@ from src.models.database import (
|
||||
ProviderEndpoint,
|
||||
RequestCandidate,
|
||||
)
|
||||
from src.api.base.context import ApiRequestContext
|
||||
from src.models.endpoint_models import (
|
||||
EndpointHealthEvent,
|
||||
EndpointHealthMonitor,
|
||||
@@ -338,7 +340,7 @@ class AdminProviderHealthMonitorAdapter(AdminApiAdapter):
|
||||
lookback_hours: int
|
||||
per_endpoint_limit: int
|
||||
|
||||
async def handle(self, context): # type: ignore[override]
|
||||
async def handle(self, context: ApiRequestContext) -> Any: # type: ignore[override]
|
||||
db = context.db
|
||||
provider = db.query(Provider).filter(Provider.id == self.provider_id).first()
|
||||
if not provider:
|
||||
@@ -447,7 +449,7 @@ class AdminProviderHealthMonitorAdapter(AdminApiAdapter):
|
||||
|
||||
|
||||
class AdminProviderSummaryAdapter(AdminApiAdapter):
|
||||
async def handle(self, context): # type: ignore[override]
|
||||
async def handle(self, context: ApiRequestContext) -> Any: # type: ignore[override]
|
||||
db = context.db
|
||||
providers = (
|
||||
db.query(Provider)
|
||||
@@ -462,7 +464,7 @@ class AdminUpdateProviderSettingsAdapter(AdminApiAdapter):
|
||||
provider_id: str
|
||||
update_data: ProviderUpdateRequest
|
||||
|
||||
async def handle(self, context): # type: ignore[override]
|
||||
async def handle(self, context: ApiRequestContext) -> Any: # type: ignore[override]
|
||||
db = context.db
|
||||
provider = db.query(Provider).filter(Provider.id == self.provider_id).first()
|
||||
if not provider:
|
||||
|
||||
@@ -4,6 +4,9 @@ IP 安全管理接口
|
||||
提供 IP 黑白名单管理和速率限制统计
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
from fastapi import APIRouter, Depends, HTTPException, Request, status
|
||||
from pydantic import BaseModel, Field, ValidationError
|
||||
from sqlalchemy.orm import Session
|
||||
@@ -14,6 +17,7 @@ from src.api.base.pipeline import ApiRequestPipeline
|
||||
from src.core.exceptions import InvalidRequestException, translate_pydantic_error
|
||||
from src.database import get_db
|
||||
from src.services.rate_limit.ip_limiter import IPRateLimiter
|
||||
from src.api.base.context import ApiRequestContext
|
||||
|
||||
router = APIRouter(prefix="/api/admin/security/ip", tags=["Admin - Security"])
|
||||
pipeline = ApiRequestPipeline()
|
||||
@@ -52,7 +56,7 @@ class RemoveIPFromWhitelistRequest(BaseModel):
|
||||
|
||||
|
||||
@router.post("/blacklist")
|
||||
async def add_to_blacklist(request: Request, db: Session = Depends(get_db)):
|
||||
async def add_to_blacklist(request: Request, db: Session = Depends(get_db)) -> None:
|
||||
"""
|
||||
添加 IP 到黑名单
|
||||
|
||||
@@ -74,7 +78,7 @@ async def add_to_blacklist(request: Request, db: Session = Depends(get_db)):
|
||||
|
||||
|
||||
@router.delete("/blacklist/{ip_address}")
|
||||
async def remove_from_blacklist(ip_address: str, request: Request, db: Session = Depends(get_db)):
|
||||
async def remove_from_blacklist(ip_address: str, request: Request, db: Session = Depends(get_db)) -> None:
|
||||
"""
|
||||
从黑名单移除 IP
|
||||
|
||||
@@ -92,7 +96,7 @@ async def remove_from_blacklist(ip_address: str, request: Request, db: Session =
|
||||
|
||||
|
||||
@router.get("/blacklist/stats")
|
||||
async def get_blacklist_stats(request: Request, db: Session = Depends(get_db)):
|
||||
async def get_blacklist_stats(request: Request, db: Session = Depends(get_db)) -> Any:
|
||||
"""
|
||||
获取黑名单统计信息
|
||||
|
||||
@@ -111,7 +115,7 @@ async def get_blacklist_stats(request: Request, db: Session = Depends(get_db)):
|
||||
|
||||
|
||||
@router.post("/whitelist")
|
||||
async def add_to_whitelist(request: Request, db: Session = Depends(get_db)):
|
||||
async def add_to_whitelist(request: Request, db: Session = Depends(get_db)) -> None:
|
||||
"""
|
||||
添加 IP 到白名单
|
||||
|
||||
@@ -129,7 +133,7 @@ async def add_to_whitelist(request: Request, db: Session = Depends(get_db)):
|
||||
|
||||
|
||||
@router.delete("/whitelist/{ip_address}")
|
||||
async def remove_from_whitelist(ip_address: str, request: Request, db: Session = Depends(get_db)):
|
||||
async def remove_from_whitelist(ip_address: str, request: Request, db: Session = Depends(get_db)) -> None:
|
||||
"""
|
||||
从白名单移除 IP
|
||||
|
||||
@@ -147,7 +151,7 @@ async def remove_from_whitelist(ip_address: str, request: Request, db: Session =
|
||||
|
||||
|
||||
@router.get("/whitelist")
|
||||
async def get_whitelist(request: Request, db: Session = Depends(get_db)):
|
||||
async def get_whitelist(request: Request, db: Session = Depends(get_db)) -> Any:
|
||||
"""
|
||||
获取白名单
|
||||
|
||||
@@ -167,7 +171,7 @@ async def get_whitelist(request: Request, db: Session = Depends(get_db)):
|
||||
class AddToBlacklistAdapter(AuthenticatedApiAdapter):
|
||||
"""添加 IP 到黑名单适配器"""
|
||||
|
||||
async def handle(self, context): # type: ignore[override]
|
||||
async def handle(self, context: ApiRequestContext) -> Any: # type: ignore[override]
|
||||
payload = context.ensure_json_body()
|
||||
try:
|
||||
req = AddIPToBlacklistRequest.model_validate(payload)
|
||||
@@ -199,7 +203,7 @@ class RemoveFromBlacklistAdapter(AuthenticatedApiAdapter):
|
||||
def __init__(self, ip_address: str):
|
||||
self.ip_address = ip_address
|
||||
|
||||
async def handle(self, context): # type: ignore[override]
|
||||
async def handle(self, context: ApiRequestContext) -> Any: # type: ignore[override]
|
||||
success = await IPRateLimiter.remove_from_blacklist(self.ip_address)
|
||||
|
||||
if not success:
|
||||
@@ -213,7 +217,7 @@ class RemoveFromBlacklistAdapter(AuthenticatedApiAdapter):
|
||||
class GetBlacklistStatsAdapter(AuthenticatedApiAdapter):
|
||||
"""获取黑名单统计适配器"""
|
||||
|
||||
async def handle(self, context): # type: ignore[override]
|
||||
async def handle(self, context: ApiRequestContext) -> Any: # type: ignore[override]
|
||||
stats = await IPRateLimiter.get_blacklist_stats()
|
||||
return stats
|
||||
|
||||
@@ -221,7 +225,7 @@ class GetBlacklistStatsAdapter(AuthenticatedApiAdapter):
|
||||
class AddToWhitelistAdapter(AuthenticatedApiAdapter):
|
||||
"""添加 IP 到白名单适配器"""
|
||||
|
||||
async def handle(self, context): # type: ignore[override]
|
||||
async def handle(self, context: ApiRequestContext) -> Any: # type: ignore[override]
|
||||
payload = context.ensure_json_body()
|
||||
try:
|
||||
req = AddIPToWhitelistRequest.model_validate(payload)
|
||||
@@ -248,7 +252,7 @@ class RemoveFromWhitelistAdapter(AuthenticatedApiAdapter):
|
||||
def __init__(self, ip_address: str):
|
||||
self.ip_address = ip_address
|
||||
|
||||
async def handle(self, context): # type: ignore[override]
|
||||
async def handle(self, context: ApiRequestContext) -> Any: # type: ignore[override]
|
||||
success = await IPRateLimiter.remove_from_whitelist(self.ip_address)
|
||||
|
||||
if not success:
|
||||
@@ -262,6 +266,6 @@ class RemoveFromWhitelistAdapter(AuthenticatedApiAdapter):
|
||||
class GetWhitelistAdapter(AuthenticatedApiAdapter):
|
||||
"""获取白名单适配器"""
|
||||
|
||||
async def handle(self, context): # type: ignore[override]
|
||||
async def handle(self, context: ApiRequestContext) -> Any: # type: ignore[override]
|
||||
whitelist = await IPRateLimiter.get_whitelist()
|
||||
return {"whitelist": list(whitelist), "total": len(whitelist)}
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
"""系统设置API端点。"""
|
||||
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
import copy
|
||||
from dataclasses import dataclass
|
||||
|
||||
@@ -17,6 +20,7 @@ from src.models.api import SystemSettingsRequest, SystemSettingsResponse
|
||||
from src.models.database import ApiKey, Provider, Usage, User
|
||||
from src.services.email.email_template import EmailTemplate
|
||||
from src.services.system.config import SystemConfigService
|
||||
from src.api.base.context import ApiRequestContext
|
||||
|
||||
router = APIRouter(prefix="/api/admin/system", tags=["Admin - System"])
|
||||
|
||||
@@ -79,7 +83,7 @@ def _parse_version(version_str: str) -> tuple:
|
||||
|
||||
|
||||
@router.get("/version")
|
||||
async def get_system_version():
|
||||
async def get_system_version() -> Any:
|
||||
"""
|
||||
获取系统版本信息
|
||||
|
||||
@@ -92,7 +96,7 @@ async def get_system_version():
|
||||
|
||||
|
||||
@router.get("/check-update")
|
||||
async def check_update():
|
||||
async def check_update() -> Any:
|
||||
"""
|
||||
检查系统更新
|
||||
|
||||
@@ -115,7 +119,7 @@ async def check_update():
|
||||
github_repo = "Aethersailor/Aether"
|
||||
github_tags_url = f"https://api.github.com/repos/{github_repo}/tags"
|
||||
|
||||
def _make_empty_response(error: str | None = None):
|
||||
def _make_empty_response(error: str | None = None) -> None:
|
||||
return {
|
||||
"current_version": current_version,
|
||||
"latest_version": None,
|
||||
@@ -238,7 +242,7 @@ pipeline = ApiRequestPipeline()
|
||||
|
||||
|
||||
@router.get("/settings")
|
||||
async def get_system_settings(request: Request, db: Session = Depends(get_db)):
|
||||
async def get_system_settings(request: Request, db: Session = Depends(get_db)) -> Any:
|
||||
"""
|
||||
获取系统设置
|
||||
|
||||
@@ -255,7 +259,7 @@ async def get_system_settings(request: Request, db: Session = Depends(get_db)):
|
||||
|
||||
|
||||
@router.put("/settings")
|
||||
async def update_system_settings(http_request: Request, db: Session = Depends(get_db)):
|
||||
async def update_system_settings(http_request: Request, db: Session = Depends(get_db)) -> None:
|
||||
"""
|
||||
更新系统设置
|
||||
|
||||
@@ -275,7 +279,7 @@ async def update_system_settings(http_request: Request, db: Session = Depends(ge
|
||||
|
||||
|
||||
@router.get("/configs")
|
||||
async def get_all_system_configs(request: Request, db: Session = Depends(get_db)):
|
||||
async def get_all_system_configs(request: Request, db: Session = Depends(get_db)) -> Any:
|
||||
"""
|
||||
获取所有系统配置
|
||||
|
||||
@@ -290,7 +294,7 @@ async def get_all_system_configs(request: Request, db: Session = Depends(get_db)
|
||||
|
||||
|
||||
@router.get("/configs/{key}")
|
||||
async def get_system_config(key: str, request: Request, db: Session = Depends(get_db)):
|
||||
async def get_system_config(key: str, request: Request, db: Session = Depends(get_db)) -> Any:
|
||||
"""
|
||||
获取特定系统配置
|
||||
|
||||
@@ -314,7 +318,7 @@ async def set_system_config(
|
||||
key: str,
|
||||
request: Request,
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
) -> Any:
|
||||
"""
|
||||
设置系统配置
|
||||
|
||||
@@ -339,7 +343,7 @@ async def set_system_config(
|
||||
|
||||
|
||||
@router.delete("/configs/{key}")
|
||||
async def delete_system_config(key: str, request: Request, db: Session = Depends(get_db)):
|
||||
async def delete_system_config(key: str, request: Request, db: Session = Depends(get_db)) -> None:
|
||||
"""
|
||||
删除系统配置
|
||||
|
||||
@@ -357,7 +361,7 @@ async def delete_system_config(key: str, request: Request, db: Session = Depends
|
||||
|
||||
|
||||
@router.get("/stats")
|
||||
async def get_system_stats(request: Request, db: Session = Depends(get_db)):
|
||||
async def get_system_stats(request: Request, db: Session = Depends(get_db)) -> Any:
|
||||
"""
|
||||
获取系统统计信息
|
||||
|
||||
@@ -374,7 +378,7 @@ async def get_system_stats(request: Request, db: Session = Depends(get_db)):
|
||||
|
||||
|
||||
@router.post("/cleanup")
|
||||
async def trigger_cleanup(request: Request, db: Session = Depends(get_db)):
|
||||
async def trigger_cleanup(request: Request, db: Session = Depends(get_db)) -> Any:
|
||||
"""
|
||||
手动触发清理任务
|
||||
|
||||
@@ -393,7 +397,7 @@ async def trigger_cleanup(request: Request, db: Session = Depends(get_db)):
|
||||
|
||||
|
||||
@router.get("/api-formats")
|
||||
async def get_api_formats(request: Request, db: Session = Depends(get_db)):
|
||||
async def get_api_formats(request: Request, db: Session = Depends(get_db)) -> Any:
|
||||
"""
|
||||
获取所有可用的 API 格式列表
|
||||
|
||||
@@ -411,35 +415,35 @@ async def get_api_formats(request: Request, db: Session = Depends(get_db)):
|
||||
|
||||
|
||||
@router.get("/config/export")
|
||||
async def export_config(request: Request, db: Session = Depends(get_db)):
|
||||
async def export_config(request: Request, db: Session = Depends(get_db)) -> Any:
|
||||
"""导出提供商和模型配置(管理员)"""
|
||||
adapter = AdminExportConfigAdapter()
|
||||
return await pipeline.run(adapter=adapter, http_request=request, db=db, mode=adapter.mode)
|
||||
|
||||
|
||||
@router.post("/config/import")
|
||||
async def import_config(request: Request, db: Session = Depends(get_db)):
|
||||
async def import_config(request: Request, db: Session = Depends(get_db)) -> Any:
|
||||
"""导入提供商和模型配置(管理员)"""
|
||||
adapter = AdminImportConfigAdapter()
|
||||
return await pipeline.run(adapter=adapter, http_request=request, db=db, mode=adapter.mode)
|
||||
|
||||
|
||||
@router.get("/users/export")
|
||||
async def export_users(request: Request, db: Session = Depends(get_db)):
|
||||
async def export_users(request: Request, db: Session = Depends(get_db)) -> Any:
|
||||
"""导出用户数据(管理员)"""
|
||||
adapter = AdminExportUsersAdapter()
|
||||
return await pipeline.run(adapter=adapter, http_request=request, db=db, mode=adapter.mode)
|
||||
|
||||
|
||||
@router.post("/users/import")
|
||||
async def import_users(request: Request, db: Session = Depends(get_db)):
|
||||
async def import_users(request: Request, db: Session = Depends(get_db)) -> Any:
|
||||
"""导入用户数据(管理员)"""
|
||||
adapter = AdminImportUsersAdapter()
|
||||
return await pipeline.run(adapter=adapter, http_request=request, db=db, mode=adapter.mode)
|
||||
|
||||
|
||||
@router.post("/smtp/test")
|
||||
async def test_smtp(request: Request, db: Session = Depends(get_db)):
|
||||
async def test_smtp(request: Request, db: Session = Depends(get_db)) -> Any:
|
||||
"""测试 SMTP 连接(管理员)"""
|
||||
adapter = AdminTestSmtpAdapter()
|
||||
return await pipeline.run(adapter=adapter, http_request=request, db=db, mode=adapter.mode)
|
||||
@@ -449,7 +453,7 @@ async def test_smtp(request: Request, db: Session = Depends(get_db)):
|
||||
|
||||
|
||||
@router.get("/email/templates")
|
||||
async def get_email_templates(request: Request, db: Session = Depends(get_db)):
|
||||
async def get_email_templates(request: Request, db: Session = Depends(get_db)) -> Any:
|
||||
"""获取所有邮件模板(管理员)"""
|
||||
adapter = AdminGetEmailTemplatesAdapter()
|
||||
return await pipeline.run(adapter=adapter, http_request=request, db=db, mode=adapter.mode)
|
||||
@@ -458,7 +462,7 @@ async def get_email_templates(request: Request, db: Session = Depends(get_db)):
|
||||
@router.get("/email/templates/{template_type}")
|
||||
async def get_email_template(
|
||||
template_type: str, request: Request, db: Session = Depends(get_db)
|
||||
):
|
||||
) -> Any:
|
||||
"""获取指定类型的邮件模板(管理员)"""
|
||||
adapter = AdminGetEmailTemplateAdapter(template_type=template_type)
|
||||
return await pipeline.run(adapter=adapter, http_request=request, db=db, mode=adapter.mode)
|
||||
@@ -467,7 +471,7 @@ async def get_email_template(
|
||||
@router.put("/email/templates/{template_type}")
|
||||
async def update_email_template(
|
||||
template_type: str, request: Request, db: Session = Depends(get_db)
|
||||
):
|
||||
) -> Any:
|
||||
"""更新邮件模板(管理员)"""
|
||||
adapter = AdminUpdateEmailTemplateAdapter(template_type=template_type)
|
||||
return await pipeline.run(adapter=adapter, http_request=request, db=db, mode=adapter.mode)
|
||||
@@ -476,7 +480,7 @@ async def update_email_template(
|
||||
@router.post("/email/templates/{template_type}/preview")
|
||||
async def preview_email_template(
|
||||
template_type: str, request: Request, db: Session = Depends(get_db)
|
||||
):
|
||||
) -> Any:
|
||||
"""预览邮件模板(管理员)"""
|
||||
adapter = AdminPreviewEmailTemplateAdapter(template_type=template_type)
|
||||
return await pipeline.run(adapter=adapter, http_request=request, db=db, mode=adapter.mode)
|
||||
@@ -485,7 +489,7 @@ async def preview_email_template(
|
||||
@router.post("/email/templates/{template_type}/reset")
|
||||
async def reset_email_template(
|
||||
template_type: str, request: Request, db: Session = Depends(get_db)
|
||||
):
|
||||
) -> Any:
|
||||
"""重置邮件模板为默认值(管理员)"""
|
||||
adapter = AdminResetEmailTemplateAdapter(template_type=template_type)
|
||||
return await pipeline.run(adapter=adapter, http_request=request, db=db, mode=adapter.mode)
|
||||
@@ -495,7 +499,7 @@ async def reset_email_template(
|
||||
|
||||
|
||||
class AdminGetSystemSettingsAdapter(AdminApiAdapter):
|
||||
async def handle(self, context): # type: ignore[override]
|
||||
async def handle(self, context: ApiRequestContext) -> Any: # type: ignore[override]
|
||||
db = context.db
|
||||
default_provider = SystemConfigService.get_default_provider(db)
|
||||
default_model = SystemConfigService.get_config(db, "default_model")
|
||||
@@ -511,7 +515,7 @@ class AdminGetSystemSettingsAdapter(AdminApiAdapter):
|
||||
|
||||
|
||||
class AdminUpdateSystemSettingsAdapter(AdminApiAdapter):
|
||||
async def handle(self, context): # type: ignore[override]
|
||||
async def handle(self, context: ApiRequestContext) -> Any: # type: ignore[override]
|
||||
db = context.db
|
||||
payload = context.ensure_json_body()
|
||||
try:
|
||||
@@ -560,7 +564,7 @@ class AdminUpdateSystemSettingsAdapter(AdminApiAdapter):
|
||||
|
||||
|
||||
class AdminGetAllConfigsAdapter(AdminApiAdapter):
|
||||
async def handle(self, context): # type: ignore[override]
|
||||
async def handle(self, context: ApiRequestContext) -> Any: # type: ignore[override]
|
||||
return SystemConfigService.get_all_configs(context.db)
|
||||
|
||||
|
||||
@@ -571,7 +575,7 @@ class AdminGetSystemConfigAdapter(AdminApiAdapter):
|
||||
# 敏感配置项,不返回实际值
|
||||
SENSITIVE_KEYS = {"smtp_password"}
|
||||
|
||||
async def handle(self, context): # type: ignore[override]
|
||||
async def handle(self, context: ApiRequestContext) -> Any: # type: ignore[override]
|
||||
value = SystemConfigService.get_config(context.db, self.key)
|
||||
if value is None:
|
||||
raise NotFoundException(f"配置项 '{self.key}' 不存在")
|
||||
@@ -588,7 +592,7 @@ class AdminSetSystemConfigAdapter(AdminApiAdapter):
|
||||
# 需要加密存储的配置项
|
||||
ENCRYPTED_KEYS = {"smtp_password"}
|
||||
|
||||
async def handle(self, context): # type: ignore[override]
|
||||
async def handle(self, context: ApiRequestContext) -> Any: # type: ignore[override]
|
||||
payload = context.ensure_json_body()
|
||||
value = payload.get("value")
|
||||
|
||||
@@ -619,7 +623,7 @@ class AdminSetSystemConfigAdapter(AdminApiAdapter):
|
||||
class AdminDeleteSystemConfigAdapter(AdminApiAdapter):
|
||||
key: str
|
||||
|
||||
async def handle(self, context): # type: ignore[override]
|
||||
async def handle(self, context: ApiRequestContext) -> Any: # type: ignore[override]
|
||||
deleted = SystemConfigService.delete_config(context.db, self.key)
|
||||
if not deleted:
|
||||
raise NotFoundException(f"配置项 '{self.key}' 不存在")
|
||||
@@ -627,7 +631,7 @@ class AdminDeleteSystemConfigAdapter(AdminApiAdapter):
|
||||
|
||||
|
||||
class AdminSystemStatsAdapter(AdminApiAdapter):
|
||||
async def handle(self, context): # type: ignore[override]
|
||||
async def handle(self, context: ApiRequestContext) -> Any: # type: ignore[override]
|
||||
db = context.db
|
||||
total_users = db.query(User).count()
|
||||
active_users = db.query(User).filter(User.is_active.is_(True)).count()
|
||||
@@ -645,7 +649,7 @@ class AdminSystemStatsAdapter(AdminApiAdapter):
|
||||
|
||||
|
||||
class AdminTriggerCleanupAdapter(AdminApiAdapter):
|
||||
async def handle(self, context): # type: ignore[override]
|
||||
async def handle(self, context: ApiRequestContext) -> Any: # type: ignore[override]
|
||||
"""手动触发清理任务"""
|
||||
from datetime import datetime, timezone
|
||||
|
||||
@@ -708,7 +712,7 @@ class AdminTriggerCleanupAdapter(AdminApiAdapter):
|
||||
|
||||
|
||||
class AdminGetApiFormatsAdapter(AdminApiAdapter):
|
||||
async def handle(self, context): # type: ignore[override]
|
||||
async def handle(self, context: ApiRequestContext) -> Any: # type: ignore[override]
|
||||
"""获取所有可用的API格式"""
|
||||
from src.core.api_format import API_FORMAT_DEFINITIONS, APIFormat
|
||||
|
||||
@@ -738,7 +742,7 @@ class AdminExportConfigAdapter(AdminApiAdapter):
|
||||
"token_cookie", "auth_cookie", "cookie_string", "cookie"
|
||||
}
|
||||
|
||||
def _decrypt_provider_config(self, config: dict, crypto_service) -> dict:
|
||||
def _decrypt_provider_config(self, config: dict, crypto_service: Any) -> dict:
|
||||
"""解密 Provider config 中的 provider_ops credentials"""
|
||||
if not config:
|
||||
return config
|
||||
@@ -762,7 +766,7 @@ class AdminExportConfigAdapter(AdminApiAdapter):
|
||||
|
||||
return decrypted_config
|
||||
|
||||
async def handle(self, context): # type: ignore[override]
|
||||
async def handle(self, context: ApiRequestContext) -> Any: # type: ignore[override]
|
||||
"""导出提供商和模型配置(解密数据)"""
|
||||
from datetime import datetime, timezone
|
||||
|
||||
@@ -976,7 +980,7 @@ class AdminImportConfigAdapter(AdminApiAdapter):
|
||||
"token_cookie", "auth_cookie", "cookie_string", "cookie"
|
||||
}
|
||||
|
||||
def _encrypt_provider_config(self, config: dict, crypto_service) -> dict:
|
||||
def _encrypt_provider_config(self, config: dict, crypto_service: Any) -> dict:
|
||||
"""加密 Provider config 中的 provider_ops credentials"""
|
||||
if not config:
|
||||
return config
|
||||
@@ -998,7 +1002,7 @@ class AdminImportConfigAdapter(AdminApiAdapter):
|
||||
|
||||
return encrypted_config
|
||||
|
||||
async def handle(self, context): # type: ignore[override]
|
||||
async def handle(self, context: ApiRequestContext) -> Any: # type: ignore[override]
|
||||
"""导入提供商和模型配置"""
|
||||
import uuid
|
||||
from datetime import datetime, timezone
|
||||
@@ -1611,7 +1615,7 @@ class AdminImportConfigAdapter(AdminApiAdapter):
|
||||
|
||||
|
||||
class AdminExportUsersAdapter(AdminApiAdapter):
|
||||
async def handle(self, context): # type: ignore[override]
|
||||
async def handle(self, context: ApiRequestContext) -> Any: # type: ignore[override]
|
||||
"""导出用户数据(保留加密数据,排除管理员)"""
|
||||
from datetime import datetime, timezone
|
||||
|
||||
@@ -1689,7 +1693,7 @@ class AdminExportUsersAdapter(AdminApiAdapter):
|
||||
|
||||
|
||||
class AdminImportUsersAdapter(AdminApiAdapter):
|
||||
async def handle(self, context): # type: ignore[override]
|
||||
async def handle(self, context: ApiRequestContext) -> Any: # type: ignore[override]
|
||||
"""导入用户数据"""
|
||||
import uuid
|
||||
from datetime import datetime, timezone
|
||||
@@ -1891,7 +1895,7 @@ class AdminImportUsersAdapter(AdminApiAdapter):
|
||||
|
||||
|
||||
class AdminTestSmtpAdapter(AdminApiAdapter):
|
||||
async def handle(self, context): # type: ignore[override]
|
||||
async def handle(self, context: ApiRequestContext) -> Any: # type: ignore[override]
|
||||
"""测试 SMTP 连接"""
|
||||
from src.core.crypto import crypto_service
|
||||
from src.services.system.config import SystemConfigService
|
||||
@@ -1968,7 +1972,7 @@ class AdminTestSmtpAdapter(AdminApiAdapter):
|
||||
class AdminGetEmailTemplatesAdapter(AdminApiAdapter):
|
||||
"""获取所有邮件模板"""
|
||||
|
||||
async def handle(self, context): # type: ignore[override]
|
||||
async def handle(self, context: ApiRequestContext) -> Any: # type: ignore[override]
|
||||
db = context.db
|
||||
templates = []
|
||||
|
||||
@@ -2003,7 +2007,7 @@ class AdminGetEmailTemplateAdapter(AdminApiAdapter):
|
||||
|
||||
template_type: str
|
||||
|
||||
async def handle(self, context): # type: ignore[override]
|
||||
async def handle(self, context: ApiRequestContext) -> Any: # type: ignore[override]
|
||||
# 验证模板类型
|
||||
if self.template_type not in EmailTemplate.TEMPLATE_TYPES:
|
||||
raise NotFoundException(f"模板类型 '{self.template_type}' 不存在")
|
||||
@@ -2036,7 +2040,7 @@ class AdminUpdateEmailTemplateAdapter(AdminApiAdapter):
|
||||
|
||||
template_type: str
|
||||
|
||||
async def handle(self, context): # type: ignore[override]
|
||||
async def handle(self, context: ApiRequestContext) -> Any: # type: ignore[override]
|
||||
# 验证模板类型
|
||||
if self.template_type not in EmailTemplate.TEMPLATE_TYPES:
|
||||
raise NotFoundException(f"模板类型 '{self.template_type}' 不存在")
|
||||
@@ -2077,7 +2081,7 @@ class AdminPreviewEmailTemplateAdapter(AdminApiAdapter):
|
||||
|
||||
template_type: str
|
||||
|
||||
async def handle(self, context): # type: ignore[override]
|
||||
async def handle(self, context: ApiRequestContext) -> Any: # type: ignore[override]
|
||||
# 验证模板类型
|
||||
if self.template_type not in EmailTemplate.TEMPLATE_TYPES:
|
||||
raise NotFoundException(f"模板类型 '{self.template_type}' 不存在")
|
||||
@@ -2123,7 +2127,7 @@ class AdminResetEmailTemplateAdapter(AdminApiAdapter):
|
||||
|
||||
template_type: str
|
||||
|
||||
async def handle(self, context): # type: ignore[override]
|
||||
async def handle(self, context: ApiRequestContext) -> Any: # type: ignore[override]
|
||||
# 验证模板类型
|
||||
if self.template_type not in EmailTemplate.TEMPLATE_TYPES:
|
||||
raise NotFoundException(f"模板类型 '{self.template_type}' 不存在")
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
"""管理员使用情况统计路由。"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
from collections import defaultdict
|
||||
from dataclasses import dataclass
|
||||
from datetime import datetime
|
||||
@@ -21,6 +24,7 @@ from src.models.database import (
|
||||
User,
|
||||
)
|
||||
from src.services.usage.service import UsageService
|
||||
from src.api.base.context import ApiRequestContext
|
||||
|
||||
router = APIRouter(prefix="/api/admin/usage", tags=["Admin - Usage"])
|
||||
pipeline = ApiRequestPipeline()
|
||||
@@ -37,7 +41,7 @@ async def get_usage_aggregation(
|
||||
end_date: datetime | None = None,
|
||||
limit: int = Query(20, ge=1, le=100),
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
) -> Any:
|
||||
"""
|
||||
获取使用情况聚合统计
|
||||
|
||||
@@ -77,7 +81,7 @@ async def get_usage_stats(
|
||||
start_date: datetime | None = None,
|
||||
end_date: datetime | None = None,
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
) -> Any:
|
||||
"""
|
||||
获取使用情况总体统计
|
||||
|
||||
@@ -105,7 +109,7 @@ async def get_usage_stats(
|
||||
async def get_activity_heatmap(
|
||||
request: Request,
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
) -> Any:
|
||||
"""
|
||||
获取活动热力图数据
|
||||
|
||||
@@ -132,7 +136,7 @@ async def get_usage_records(
|
||||
limit: int = Query(100, ge=1, le=500),
|
||||
offset: int = Query(0, ge=0),
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
) -> Any:
|
||||
"""
|
||||
获取使用记录列表
|
||||
|
||||
@@ -180,7 +184,7 @@ async def get_active_requests(
|
||||
request: Request,
|
||||
ids: str | None = Query(None, description="逗号分隔的请求 ID 列表,用于查询特定请求的状态"),
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
) -> Any:
|
||||
"""
|
||||
获取活跃请求的状态
|
||||
|
||||
@@ -207,7 +211,7 @@ async def get_usage_detail(
|
||||
usage_id: str,
|
||||
request: Request,
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
) -> Any:
|
||||
"""
|
||||
获取使用记录详情
|
||||
|
||||
@@ -262,7 +266,7 @@ class AdminUsageStatsAdapter(AdminApiAdapter):
|
||||
self.start_date = start_date
|
||||
self.end_date = end_date
|
||||
|
||||
async def handle(self, context): # type: ignore[override]
|
||||
async def handle(self, context: ApiRequestContext) -> Any: # type: ignore[override]
|
||||
db = context.db
|
||||
query = db.query(Usage)
|
||||
if self.start_date:
|
||||
@@ -327,7 +331,7 @@ class AdminUsageStatsAdapter(AdminApiAdapter):
|
||||
class AdminActivityHeatmapAdapter(AdminApiAdapter):
|
||||
"""Activity heatmap adapter with Redis caching."""
|
||||
|
||||
async def handle(self, context): # type: ignore[override]
|
||||
async def handle(self, context: ApiRequestContext) -> Any: # type: ignore[override]
|
||||
result = await UsageService.get_cached_heatmap(
|
||||
db=context.db,
|
||||
user_id=None,
|
||||
@@ -343,7 +347,7 @@ class AdminUsageByModelAdapter(AdminApiAdapter):
|
||||
self.end_date = end_date
|
||||
self.limit = limit
|
||||
|
||||
async def handle(self, context): # type: ignore[override]
|
||||
async def handle(self, context: ApiRequestContext) -> Any: # type: ignore[override]
|
||||
db = context.db
|
||||
query = db.query(
|
||||
Usage.model,
|
||||
@@ -390,7 +394,7 @@ class AdminUsageByUserAdapter(AdminApiAdapter):
|
||||
self.end_date = end_date
|
||||
self.limit = limit
|
||||
|
||||
async def handle(self, context): # type: ignore[override]
|
||||
async def handle(self, context: ApiRequestContext) -> Any: # type: ignore[override]
|
||||
db = context.db
|
||||
query = (
|
||||
db.query(
|
||||
@@ -440,7 +444,7 @@ class AdminUsageByProviderAdapter(AdminApiAdapter):
|
||||
self.end_date = end_date
|
||||
self.limit = limit
|
||||
|
||||
async def handle(self, context): # type: ignore[override]
|
||||
async def handle(self, context: ApiRequestContext) -> Any: # type: ignore[override]
|
||||
db = context.db
|
||||
|
||||
# 从 request_candidates 表统计每个 Provider 的尝试次数和成功率
|
||||
@@ -554,7 +558,7 @@ class AdminUsageByApiFormatAdapter(AdminApiAdapter):
|
||||
self.end_date = end_date
|
||||
self.limit = limit
|
||||
|
||||
async def handle(self, context): # type: ignore[override]
|
||||
async def handle(self, context: ApiRequestContext) -> Any: # type: ignore[override]
|
||||
db = context.db
|
||||
query = db.query(
|
||||
Usage.api_format,
|
||||
@@ -629,7 +633,7 @@ class AdminUsageRecordsAdapter(AdminApiAdapter):
|
||||
self.limit = limit
|
||||
self.offset = offset
|
||||
|
||||
async def handle(self, context): # type: ignore[override]
|
||||
async def handle(self, context: ApiRequestContext) -> Any: # type: ignore[override]
|
||||
from sqlalchemy import or_
|
||||
|
||||
from src.utils.database_helpers import escape_like_pattern, safe_truncate_escaped
|
||||
@@ -879,7 +883,7 @@ class AdminActiveRequestsAdapter(AdminApiAdapter):
|
||||
def __init__(self, ids: str | None):
|
||||
self.ids = ids
|
||||
|
||||
async def handle(self, context): # type: ignore[override]
|
||||
async def handle(self, context: ApiRequestContext) -> Any: # type: ignore[override]
|
||||
from src.services.usage import UsageService
|
||||
|
||||
db = context.db
|
||||
@@ -901,7 +905,7 @@ class AdminUsageDetailAdapter(AdminApiAdapter):
|
||||
|
||||
usage_id: str
|
||||
|
||||
async def handle(self, context): # type: ignore[override]
|
||||
async def handle(self, context: ApiRequestContext) -> Any: # type: ignore[override]
|
||||
db = context.db
|
||||
usage_record = db.query(Usage).filter(Usage.id == self.usage_id).first()
|
||||
if not usage_record:
|
||||
@@ -972,7 +976,7 @@ class AdminUsageDetailAdapter(AdminApiAdapter):
|
||||
"tiered_pricing": tiered_pricing_info,
|
||||
}
|
||||
|
||||
async def _get_tiered_pricing_info(self, db, usage_record) -> dict | None:
|
||||
async def _get_tiered_pricing_info(self, db: Session, usage_record: Any) -> dict | None:
|
||||
"""获取阶梯计费信息"""
|
||||
from src.services.model.cost import ModelCostService
|
||||
|
||||
@@ -1036,7 +1040,7 @@ async def analyze_cache_affinity_ttl(
|
||||
api_key_id: str | None = Query(None, description="指定 API Key ID"),
|
||||
hours: int = Query(168, ge=1, le=720, description="分析最近多少小时的数据"),
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
) -> Any:
|
||||
"""
|
||||
分析用户请求间隔分布,推荐合适的缓存亲和性 TTL。
|
||||
|
||||
@@ -1060,7 +1064,7 @@ async def analyze_cache_hit(
|
||||
api_key_id: str | None = Query(None, description="指定 API Key ID"),
|
||||
hours: int = Query(168, ge=1, le=720, description="分析最近多少小时的数据"),
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
) -> Any:
|
||||
"""
|
||||
分析缓存命中情况。
|
||||
|
||||
@@ -1087,7 +1091,7 @@ class CacheAffinityTTLAnalysisAdapter(AdminApiAdapter):
|
||||
self.api_key_id = api_key_id
|
||||
self.hours = hours
|
||||
|
||||
async def handle(self, context): # type: ignore[override]
|
||||
async def handle(self, context: ApiRequestContext) -> Any: # type: ignore[override]
|
||||
db = context.db
|
||||
|
||||
result = UsageService.analyze_cache_affinity_ttl(
|
||||
@@ -1121,7 +1125,7 @@ class CacheHitAnalysisAdapter(AdminApiAdapter):
|
||||
self.api_key_id = api_key_id
|
||||
self.hours = hours
|
||||
|
||||
async def handle(self, context): # type: ignore[override]
|
||||
async def handle(self, context: ApiRequestContext) -> Any: # type: ignore[override]
|
||||
db = context.db
|
||||
|
||||
result = UsageService.get_cache_hit_analysis(
|
||||
@@ -1149,7 +1153,7 @@ async def get_interval_timeline(
|
||||
user_id: str | None = Query(None, description="指定用户 ID"),
|
||||
include_user_info: bool = Query(False, description="是否包含用户信息(用于管理员多用户视图)"),
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
) -> Any:
|
||||
"""
|
||||
获取请求间隔时间线数据,用于散点图展示。
|
||||
|
||||
@@ -1184,7 +1188,7 @@ class IntervalTimelineAdapter(AdminApiAdapter):
|
||||
self.user_id = user_id
|
||||
self.include_user_info = include_user_info
|
||||
|
||||
async def handle(self, context): # type: ignore[override]
|
||||
async def handle(self, context: ApiRequestContext) -> Any: # type: ignore[override]
|
||||
db = context.db
|
||||
|
||||
result = UsageService.get_interval_timeline(
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
"""用户管理 API 端点。"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
from datetime import datetime, timezone
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, Query, Request, status
|
||||
@@ -17,6 +20,7 @@ from src.models.database import ApiKey, User, UserRole
|
||||
from src.services.system.config import SystemConfigService
|
||||
from src.services.user.apikey import ApiKeyService
|
||||
from src.services.user.service import UserService
|
||||
from src.api.base.context import ApiRequestContext
|
||||
|
||||
|
||||
router = APIRouter(prefix="/api/admin/users", tags=["Admin - Users"])
|
||||
@@ -25,7 +29,7 @@ pipeline = ApiRequestPipeline()
|
||||
|
||||
# 管理员端点
|
||||
@router.post("")
|
||||
async def create_user_endpoint(request: Request, db: Session = Depends(get_db)):
|
||||
async def create_user_endpoint(request: Request, db: Session = Depends(get_db)) -> Any:
|
||||
"""
|
||||
创建用户
|
||||
|
||||
@@ -50,7 +54,7 @@ async def list_users(
|
||||
role: str | None = Query(None, description="按角色筛选(user/admin)"),
|
||||
is_active: bool | None = Query(None, description="按状态筛选"),
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
) -> Any:
|
||||
"""
|
||||
获取用户列表
|
||||
|
||||
@@ -63,7 +67,7 @@ async def list_users(
|
||||
|
||||
|
||||
@router.get("/{user_id}")
|
||||
async def get_user(user_id: str, request: Request, db: Session = Depends(get_db)):
|
||||
async def get_user(user_id: str, request: Request, db: Session = Depends(get_db)) -> Any:
|
||||
"""
|
||||
获取用户详情
|
||||
|
||||
@@ -81,7 +85,7 @@ async def update_user(
|
||||
user_id: str,
|
||||
request: Request,
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
) -> Any:
|
||||
"""
|
||||
更新用户信息
|
||||
|
||||
@@ -104,7 +108,7 @@ async def update_user(
|
||||
|
||||
|
||||
@router.delete("/{user_id}")
|
||||
async def delete_user(user_id: str, request: Request, db: Session = Depends(get_db)):
|
||||
async def delete_user(user_id: str, request: Request, db: Session = Depends(get_db)) -> None:
|
||||
"""
|
||||
删除用户
|
||||
|
||||
@@ -118,7 +122,7 @@ async def delete_user(user_id: str, request: Request, db: Session = Depends(get_
|
||||
|
||||
|
||||
@router.patch("/{user_id}/quota")
|
||||
async def reset_user_quota(user_id: str, request: Request, db: Session = Depends(get_db)):
|
||||
async def reset_user_quota(user_id: str, request: Request, db: Session = Depends(get_db)) -> None:
|
||||
"""
|
||||
重置用户配额
|
||||
|
||||
@@ -137,7 +141,7 @@ async def get_user_api_keys(
|
||||
request: Request,
|
||||
is_active: bool | None = Query(None, description="按状态筛选"),
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
) -> Any:
|
||||
"""
|
||||
获取用户的 API 密钥列表
|
||||
|
||||
@@ -155,7 +159,7 @@ async def create_user_api_key(
|
||||
user_id: str,
|
||||
request: Request,
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
) -> Any:
|
||||
"""
|
||||
为用户创建 API 密钥
|
||||
|
||||
@@ -183,7 +187,7 @@ async def delete_user_api_key(
|
||||
key_id: str,
|
||||
request: Request,
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
) -> Any:
|
||||
"""
|
||||
删除用户的 API 密钥
|
||||
|
||||
@@ -201,7 +205,7 @@ async def delete_user_api_key(
|
||||
|
||||
|
||||
class AdminCreateUserAdapter(AdminApiAdapter):
|
||||
async def handle(self, context): # type: ignore[override]
|
||||
async def handle(self, context: ApiRequestContext) -> Any: # type: ignore[override]
|
||||
db = context.db
|
||||
payload = context.ensure_json_body()
|
||||
try:
|
||||
@@ -279,7 +283,7 @@ class AdminListUsersAdapter(AdminApiAdapter):
|
||||
self.role = role
|
||||
self.is_active = is_active
|
||||
|
||||
async def handle(self, context): # type: ignore[override]
|
||||
async def handle(self, context: ApiRequestContext) -> Any: # type: ignore[override]
|
||||
db = context.db
|
||||
role_enum = UserRole[self.role.upper()] if self.role else None
|
||||
users = UserService.list_users(db, self.skip, self.limit, role_enum, self.is_active)
|
||||
@@ -306,7 +310,7 @@ class AdminGetUserAdapter(AdminApiAdapter):
|
||||
def __init__(self, user_id: str):
|
||||
self.user_id = user_id
|
||||
|
||||
async def handle(self, context): # type: ignore[override]
|
||||
async def handle(self, context: ApiRequestContext) -> Any: # type: ignore[override]
|
||||
db = context.db
|
||||
user = UserService.get_user(db, self.user_id)
|
||||
if not user:
|
||||
@@ -341,7 +345,7 @@ class AdminUpdateUserAdapter(AdminApiAdapter):
|
||||
def __init__(self, user_id: str):
|
||||
self.user_id = user_id
|
||||
|
||||
async def handle(self, context): # type: ignore[override]
|
||||
async def handle(self, context: ApiRequestContext) -> Any: # type: ignore[override]
|
||||
db = context.db
|
||||
existing_user = UserService.get_user(db, self.user_id)
|
||||
if not existing_user:
|
||||
@@ -406,7 +410,7 @@ class AdminDeleteUserAdapter(AdminApiAdapter):
|
||||
def __init__(self, user_id: str):
|
||||
self.user_id = user_id
|
||||
|
||||
async def handle(self, context): # type: ignore[override]
|
||||
async def handle(self, context: ApiRequestContext) -> Any: # type: ignore[override]
|
||||
db = context.db
|
||||
user = UserService.get_user(db, self.user_id)
|
||||
if not user:
|
||||
@@ -435,7 +439,7 @@ class AdminResetUserQuotaAdapter(AdminApiAdapter):
|
||||
def __init__(self, user_id: str):
|
||||
self.user_id = user_id
|
||||
|
||||
async def handle(self, context): # type: ignore[override]
|
||||
async def handle(self, context: ApiRequestContext) -> Any: # type: ignore[override]
|
||||
db = context.db
|
||||
user = UserService.get_user(db, self.user_id)
|
||||
if not user:
|
||||
@@ -470,7 +474,7 @@ class AdminGetUserKeysAdapter(AdminApiAdapter):
|
||||
self.user_id = user_id
|
||||
self.is_active = is_active
|
||||
|
||||
async def handle(self, context): # type: ignore[override]
|
||||
async def handle(self, context: ApiRequestContext) -> Any: # type: ignore[override]
|
||||
db = context.db
|
||||
|
||||
# 验证用户存在
|
||||
@@ -518,7 +522,7 @@ class AdminCreateUserKeyAdapter(AdminApiAdapter):
|
||||
def __init__(self, user_id: str):
|
||||
self.user_id = user_id
|
||||
|
||||
async def handle(self, context): # type: ignore[override]
|
||||
async def handle(self, context: ApiRequestContext) -> Any: # type: ignore[override]
|
||||
db = context.db
|
||||
payload = context.ensure_json_body()
|
||||
try:
|
||||
@@ -574,7 +578,7 @@ class AdminDeleteUserKeyAdapter(AdminApiAdapter):
|
||||
self.user_id = user_id
|
||||
self.key_id = key_id
|
||||
|
||||
async def handle(self, context): # type: ignore[override]
|
||||
async def handle(self, context: ApiRequestContext) -> Any: # type: ignore[override]
|
||||
db = context.db
|
||||
|
||||
# 验证Key存在且属于该用户
|
||||
|
||||
Reference in New Issue
Block a user