refactor(db): 修复异步连接池无界增长,并完成 SQLAlchemy 2.0 迁移与分层归位 (#6320)

This commit is contained in:
Aqr-K
2026-08-15 06:58:38 +08:00
committed by GitHub
parent e28de9cfe1
commit 8a11214a43
252 changed files with 11405 additions and 2889 deletions
+120
View File
@@ -0,0 +1,120 @@
"""
API 层的公共依赖。
这些是 FastAPI 的路由依赖:从令牌解出用户、校验激活状态与权限,失败一律以
HTTPException 表达。它们此前住在 app/db/oper/user.py 里,与数据访问混在一处——
鉴权是 HTTP 层的关注点,产出的是 403/400 而不是数据。放在 db 包里既让数据层反向
依赖了 fastapi,也使这部分逻辑无法与数据访问分开度量。
"""
from fastapi import Depends, HTTPException
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.orm import Session
from app import schemas
from app.application.security.access import verify_token
from app.db import get_async_db, get_db
from app.db.models.user import User
def get_current_user(
db: Session = Depends(get_db),
token_data: schemas.TokenPayload = Depends(verify_token)
) -> User:
"""
获取当前用户
"""
user = User.get(db, rid=token_data.sub)
if not user:
raise HTTPException(status_code=403, detail="用户不存在")
return user
async def get_current_user_async(
db: AsyncSession = Depends(get_async_db),
token_data: schemas.TokenPayload = Depends(verify_token)
) -> User:
"""
异步获取当前用户
"""
user = await User.async_get(db, rid=token_data.sub)
if not user:
raise HTTPException(status_code=403, detail="用户不存在")
return user
def get_current_active_user(
current_user: User = Depends(get_current_user),
) -> User:
"""
获取当前激活用户
"""
if not current_user.is_active:
raise HTTPException(status_code=403, detail="用户未激活")
return current_user
async def get_current_active_user_async(
current_user: User = Depends(get_current_user_async),
) -> User:
"""
异步获取当前激活用户
"""
if not current_user.is_active:
raise HTTPException(status_code=403, detail="用户未激活")
return current_user
def _ensure_manage_user(current_user: User) -> User:
"""
校验用户具备全局管理权限。
"""
permissions = current_user.permissions or {}
if not current_user.is_superuser and not bool(permissions.get("manage")):
raise HTTPException(
status_code=400, detail="用户权限不足"
)
return current_user
def get_current_active_manage_user(
current_user: User = Depends(get_current_active_user),
) -> User:
"""
获取当前拥有管理权限的激活用户。
"""
return _ensure_manage_user(current_user)
async def get_current_active_manage_user_async(
current_user: User = Depends(get_current_active_user_async),
) -> User:
"""
异步获取当前拥有管理权限的激活用户。
"""
return _ensure_manage_user(current_user)
def get_current_active_superuser(
current_user: User = Depends(get_current_user),
) -> User:
"""
获取当前激活超级管理员
"""
if not current_user.is_superuser:
raise HTTPException(
status_code=400, detail="用户权限不足"
)
return current_user
async def get_current_active_superuser_async(
current_user: User = Depends(get_current_user_async),
) -> User:
"""
异步获取当前激活超级管理员
"""
if not current_user.is_superuser:
raise HTTPException(
status_code=400, detail="用户权限不足"
)
return current_user
+3 -2
View File
@@ -32,10 +32,11 @@ from app.command import Command
from app.runtime.config import global_vars, settings
from app.runtime.events import Event, EventManager
from app.db import get_async_db
from app.db.agentchat_oper import AgentChatOper
from app.db.oper.agentchat import AgentChatOper
from app.db.models import User
from app.db.models.agentchat import AgentChat
from app.db.user_oper import UserOper, get_current_active_user
from app.db.oper.user import UserOper
from app.api.deps import get_current_active_user
from app.application.messaging.agent import attach_web_agent_edit_queue, detach_web_agent_edit_queue
from app.application.messaging.interaction import agent_interaction_manager, media_interaction_manager
from app.runtime.localization import LocaleHelper
+1 -1
View File
@@ -12,7 +12,7 @@ from app.runtime.config import settings
from app.application.security.access import verify_apitoken
from app.db import get_db
from app.db.models.transferhistory import TransferHistory
from app.db.user_oper import get_current_active_superuser
from app.api.deps import get_current_active_superuser
from app.application.directory import DirectoryHelper
from app.scheduler import Scheduler
from app.adapters.system.host import SystemUtils
+3 -3
View File
@@ -11,9 +11,9 @@ from app.domain.meta.metamusic import MetaMusic
from app.domain.metainfo import MetaInfo
from app.application.security.access import verify_token
from app.db.models.user import User
from app.db.site_oper import SiteOper
from app.db.systemconfig_oper import SystemConfigOper
from app.db.user_oper import get_current_active_user
from app.db.oper.site import SiteOper
from app.db.oper.systemconfig import SystemConfigOper
from app.api.deps import get_current_active_user
from app.application.directory import DirectoryHelper
from app.schemas.types import (
MUSIC_ENTITY_RECORDING,
+1 -1
View File
@@ -22,7 +22,7 @@ from app.db import get_async_db, get_db
from app.db.models import User
from app.db.models.downloadhistory import DownloadHistory, DownloadFiles
from app.db.models.transferhistory import TransferHistory
from app.db.user_oper import (
from app.api.deps import (
get_current_active_manage_user,
get_current_active_superuser,
get_current_active_superuser_async,
+1 -4
View File
@@ -15,10 +15,7 @@ from app.agent.llm import (
)
from app.runtime.config import settings
from app.db.models import User
from app.db.user_oper import (
get_current_active_superuser_async,
get_current_active_user_async,
)
from app.api.deps import get_current_active_superuser_async, get_current_active_user_async
from app.runtime.log import logger
router = ResponseAPIRouter()
+1 -1
View File
@@ -10,7 +10,7 @@ from app.api.response import RAW_RESPONSE_OPENAPI_KEY, ResponseAPIRouter
from app.chain.user import MfaRequired, UserChain
from app.application.security import access as security
from app.runtime.config import settings
from app.db.systemconfig_oper import SystemConfigOper
from app.db.oper.systemconfig import SystemConfigOper
from app.application.site.sites import SitesHelper # pylint: disable=no-name-in-module
from app.application.image import WallpaperHelper
from app.schemas.types import SystemConfigKey
+3 -8
View File
@@ -17,17 +17,12 @@ from app.domain.meta.metamusic import MetaMusic
from app.domain.metainfo import MetaInfo, MetaInfoPath
from app.application.security.access import verify_token, verify_apitoken
from app.db.models import User
from app.db.user_oper import get_current_active_user, get_current_active_superuser
from app.api.deps import get_current_active_user, get_current_active_superuser
from app.schemas import MediaType
from app.schemas.category import CategoryConfig
from app.schemas.types import MUSIC_ENTITY_RECORDING, MediaSource
from app.domain.media import (
is_music_media_source,
normalize_media_source,
normalize_music_type,
parse_media_source_selection,
resolve_media_identity,
)
from app.domain.media import is_music_media_source, normalize_music_type, parse_media_source_selection
from app.schemas.media import normalize_media_source, resolve_media_identity
router = ResponseAPIRouter()
+3 -3
View File
@@ -11,13 +11,13 @@ from app.domain.context import MediaInfo
from app.domain.metainfo import MetaInfo
from app.application.security.access import verify_token
from app.db import get_async_db
from app.db.mediaserver_oper import MediaServerOper
from app.db.oper.mediaserver import MediaServerOper
from app.db.models import MediaServerItem
from app.db.systemconfig_oper import SystemConfigOper
from app.db.oper.systemconfig import SystemConfigOper
from app.application.mediaserver import MediaServerHelper
from app.schemas import MediaType, NotExistMediaInfo
from app.schemas.types import MediaSource, SystemConfigKey
from app.domain.media import build_media_key, resolve_media_identity
from app.schemas.media import build_media_key, resolve_media_identity
router = ResponseAPIRouter()
+3 -3
View File
@@ -14,9 +14,9 @@ from app.runtime.config import settings, global_vars
from app.application.security.access import verify_token, verify_apitoken
from app.db import get_async_db
from app.db.models import User
from app.db.message_oper import MessageOper
from app.db.systemconfig_oper import SystemConfigOper
from app.db.user_oper import get_current_active_superuser
from app.db.oper.message import MessageOper
from app.db.oper.systemconfig import SystemConfigOper
from app.api.deps import get_current_active_superuser
from app.runtime.extensions.service_registry import ServiceConfigHelper
from app.runtime.log import logger
from app.modules.wechat.WXBizMsgCrypt3 import WXBizMsgCrypt
+2 -2
View File
@@ -18,8 +18,8 @@ from app.runtime.config import settings
from app.db import get_async_db
from app.db.models.passkey import PassKey
from app.db.models.user import User
from app.db.systemconfig_oper import SystemConfigOper
from app.db.user_oper import get_current_active_user, get_current_active_user_async
from app.db.oper.systemconfig import SystemConfigOper
from app.api.deps import get_current_active_user, get_current_active_user_async
from app.application.security.passkey import (
PassKeyHelper,
PassKeyRegistrationOriginMismatchError,
+1 -1
View File
@@ -10,7 +10,7 @@ from app.schemas.types import MediaSource, MediaType
from app.domain.context import MusicAlbumInfo, MusicArtistInfo, MusicInfo
from app.application.security.access import verify_token
from app.db.models.user import User
from app.db.user_oper import get_current_active_superuser_async
from app.api.deps import get_current_active_superuser_async
from app.modules.listenbrainz import (
LISTENBRAINZ_CHART_RANGES,
LISTENBRAINZ_FRESH_MAX_DAYS,
+1 -1
View File
@@ -6,7 +6,7 @@ from app import schemas
from app.api.response import ResponseAPIRouter
from app.runtime.extensions.module_manager import ModuleManager
from app.db.models import User
from app.db.user_oper import get_current_active_superuser
from app.api.deps import get_current_active_superuser
from app.modules.wechatclawbot.wechatclawbot import WechatClawBot
router = ResponseAPIRouter()
+2 -5
View File
@@ -24,11 +24,8 @@ from app.application.security.access import (
verify_token,
)
from app.db.models import User
from app.db.systemconfig_oper import SystemConfigOper
from app.db.user_oper import (
get_current_active_superuser,
get_current_active_superuser_async,
)
from app.db.oper.systemconfig import SystemConfigOper
from app.api.deps import get_current_active_superuser, get_current_active_superuser_async
from app.factory import app
from app.adapters.external.server import MoviePilotServerHelper
from app.adapters.external.market import PluginHelper
+2 -1
View File
@@ -14,7 +14,8 @@ from app.application.security.access import verify_resource_token, verify_token
from app.runtime.localization import LocaleHelper
from app.runtime.log import logger
from app.schemas.types import MediaSource, MediaType
from app.domain.media import normalize_music_type, resolve_media_identity
from app.domain.media import normalize_music_type
from app.schemas.media import resolve_media_identity
from app.application.security.url import SecurityUtils
router = ResponseAPIRouter()
+3 -3
View File
@@ -20,9 +20,9 @@ from app.db.models.site import Site
from app.db.models.siteicon import SiteIcon
from app.db.models.sitestatistic import SiteStatistic
from app.db.models.siteuserdata import SiteUserData
from app.db.site_oper import SiteOper
from app.db.systemconfig_oper import SystemConfigOper
from app.db.user_oper import (
from app.db.oper.site import SiteOper
from app.db.oper.systemconfig import SystemConfigOper
from app.api.deps import (
get_current_active_manage_user,
get_current_active_manage_user_async,
get_current_active_superuser,
+1 -1
View File
@@ -15,7 +15,7 @@ from app.chain.transfer import TransferChain
from app.runtime.config import settings
from app.application.security.access import verify_token
from app.db.models import User
from app.db.user_oper import (
from app.api.deps import (
get_current_active_manage_user,
get_current_active_superuser,
get_current_active_superuser_async,
+3 -3
View File
@@ -17,8 +17,8 @@ from app.db import get_async_db, get_db
from app.db.models.subscribe import Subscribe
from app.db.models.subscribehistory import SubscribeHistory
from app.db.models.user import User
from app.db.systemconfig_oper import SystemConfigOper
from app.db.user_oper import get_current_active_user, get_current_active_user_async
from app.db.oper.systemconfig import SystemConfigOper
from app.api.deps import get_current_active_user, get_current_active_user_async
from app.adapters.external.server import MoviePilotServerHelper
from app.runtime.log import logger
from app.scheduler import Scheduler
@@ -31,7 +31,7 @@ from app.schemas.types import (
EventType,
SystemConfigKey,
)
from app.domain.media import normalize_media_source, resolve_media_identity
from app.schemas.media import normalize_media_source, resolve_media_identity
router = ResponseAPIRouter()
+2 -6
View File
@@ -29,12 +29,8 @@ from app.domain.metainfo import MetaInfo
from app.runtime.extensions.module_manager import ModuleManager
from app.application.security.access import verify_apitoken, verify_resource_token, verify_token
from app.db.models import User
from app.db.systemconfig_oper import SystemConfigOper
from app.db.user_oper import (
get_current_active_superuser,
get_current_active_superuser_async,
get_current_active_user_async,
)
from app.db.oper.systemconfig import SystemConfigOper
from app.api.deps import get_current_active_superuser, get_current_active_superuser_async, get_current_active_user_async
from app.application.image import ImageHelper
from app.runtime.localization import LocaleHelper
from app.adapters.external.market import (
+2 -2
View File
@@ -8,8 +8,8 @@ from app.chain.tmdb import TmdbChain
from app.runtime.config import settings
from app.application.security.access import verify_token
from app.db.models.user import User
from app.db.systemconfig_oper import SystemConfigOper
from app.db.user_oper import get_current_active_superuser_async
from app.db.oper.systemconfig import SystemConfigOper
from app.api.deps import get_current_active_superuser_async
from app.modules.themoviedb.tmdb_cache import TmdbCache
from app.schemas.types import MediaType, SystemConfigKey
+3 -9
View File
@@ -11,10 +11,7 @@ from app.domain.context import MediaInfo, MusicInfo
from app.domain.meta.metamusic import MetaMusic
from app.domain.metainfo import MetaInfo
from app.db.models import User
from app.db.user_oper import (
get_current_active_superuser,
get_current_active_superuser_async,
)
from app.api.deps import get_current_active_superuser, get_current_active_superuser_async
from app.schemas.types import (
MUSIC_ENTITY_RECORDING,
MediaSource,
@@ -22,11 +19,8 @@ from app.schemas.types import (
MusicTargetEntityType,
)
from app.foundation.crypto import HashUtils
from app.domain.media import (
is_music_media_source,
normalize_music_type,
resolve_media_identity,
)
from app.domain.media import is_music_media_source, normalize_music_type
from app.schemas.media import resolve_media_identity
router = ResponseAPIRouter()
+1 -4
View File
@@ -13,10 +13,7 @@ from app.application.security.access import verify_token, verify_apitoken
from app.db import get_db
from app.db.models import User
from app.db.models.transferhistory import TransferHistory
from app.db.user_oper import (
get_current_active_manage_user,
get_current_active_superuser,
)
from app.api.deps import get_current_active_manage_user, get_current_active_superuser
from app.application.directory import DirectoryHelper
from app.runtime.log import logger
from app.schemas import (
+2 -6
View File
@@ -10,12 +10,8 @@ from app.api.response import ResponseAPIRouter
from app.application.security.access import get_password_hash
from app.db import get_async_db
from app.db.models.user import User
from app.db.user_oper import (
get_current_active_superuser_async,
get_current_active_user_async,
get_current_active_user,
)
from app.db.userconfig_oper import UserConfigOper
from app.api.deps import get_current_active_superuser_async, get_current_active_user_async, get_current_active_user
from app.db.oper.userconfig import UserConfigOper
router = ResponseAPIRouter()
+3 -6
View File
@@ -14,12 +14,9 @@ from app.runtime.extensions.plugin_manager import PluginManager
from app.workflow import WorkFlowManager
from app.db import get_async_db, get_db
from app.db.models import Workflow, User
from app.db.systemconfig_oper import SystemConfigOper
from app.db.user_oper import (
get_current_active_manage_user,
get_current_active_manage_user_async,
)
from app.db.workflow_oper import WorkflowOper
from app.db.oper.systemconfig import SystemConfigOper
from app.api.deps import get_current_active_manage_user, get_current_active_manage_user_async
from app.db.oper.workflow import WorkflowOper
from app.adapters.external.server import MoviePilotServerHelper
from app.scheduler import Scheduler
from app.schemas.types import EventType, EVENT_TYPE_NAMES