All checks were successful
Test / test (push) Successful in 1m45s
- Migrate SQLModel base classes, mixins, and database management to external sqlmodel-ext package; remove sqlmodels/base/, sqlmodels/mixin/, and sqlmodels/database.py - Add file viewer/editor system with WOPI protocol support for collaborative editing (OnlyOffice, Collabora) - Add enterprise edition license verification module (ee/) - Add Dockerfile multi-stage build with Cython compilation support - Add new dependencies: sqlmodel-ext, cryptography, whatthepatch Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
126 lines
4.6 KiB
Python
126 lines
4.6 KiB
Python
"""
|
||
FastAPI 依赖注入
|
||
|
||
包含 HTTP 端点的通用依赖:
|
||
- SessionDep: 数据库会话依赖
|
||
- TimeFilterRequestDep: 时间筛选查询依赖(用于 count 等统计接口)
|
||
- TableViewRequestDep: 分页排序查询依赖(包含时间筛选 + 分页排序)
|
||
- UserFilterParamsDep: 用户筛选参数依赖(用于管理员用户列表)
|
||
- require_captcha: 验证码校验依赖注入工厂
|
||
"""
|
||
from collections.abc import Awaitable, Callable
|
||
from datetime import datetime
|
||
from typing import Annotated, Literal, TypeAlias
|
||
from uuid import UUID
|
||
|
||
from fastapi import Depends, Form, Query
|
||
from sqlmodel.ext.asyncio.session import AsyncSession
|
||
|
||
from sqlmodels.database_connection import DatabaseManager
|
||
from sqlmodel_ext import TimeFilterRequest, TableViewRequest
|
||
from sqlmodels.user import UserFilterParams, UserStatus
|
||
|
||
|
||
# --- 数据库会话依赖 ---
|
||
|
||
SessionDep: TypeAlias = Annotated[AsyncSession, Depends(DatabaseManager.get_session)]
|
||
"""数据库会话依赖,用于路由函数中获取数据库会话"""
|
||
|
||
|
||
# --- 时间筛选依赖 ---
|
||
|
||
async def _get_time_filter_queries(
|
||
created_after_datetime: Annotated[datetime | None, Query()] = None,
|
||
created_before_datetime: Annotated[datetime | None, Query()] = None,
|
||
updated_after_datetime: Annotated[datetime | None, Query()] = None,
|
||
updated_before_datetime: Annotated[datetime | None, Query()] = None,
|
||
) -> TimeFilterRequest:
|
||
"""解析时间筛选查询参数"""
|
||
return TimeFilterRequest(
|
||
created_after_datetime=created_after_datetime,
|
||
created_before_datetime=created_before_datetime,
|
||
updated_after_datetime=updated_after_datetime,
|
||
updated_before_datetime=updated_before_datetime,
|
||
)
|
||
|
||
|
||
TimeFilterRequestDep: TypeAlias = Annotated[TimeFilterRequest, Depends(_get_time_filter_queries)]
|
||
"""获取时间筛选参数的依赖(用于 count 等统计接口)"""
|
||
|
||
|
||
# --- 分页排序依赖 ---
|
||
|
||
async def _get_table_view_queries(
|
||
offset: Annotated[int | None, Query(ge=0)] = 0,
|
||
limit: Annotated[int | None, Query(ge=1, le=100)] = 20,
|
||
desc: bool | None = True,
|
||
order: Literal["created_at", "updated_at"] | None = "created_at",
|
||
created_after_datetime: Annotated[datetime | None, Query()] = None,
|
||
created_before_datetime: Annotated[datetime | None, Query()] = None,
|
||
updated_after_datetime: Annotated[datetime | None, Query()] = None,
|
||
updated_before_datetime: Annotated[datetime | None, Query()] = None,
|
||
) -> TableViewRequest:
|
||
"""解析分页排序和时间筛选查询参数"""
|
||
return TableViewRequest(
|
||
offset=offset,
|
||
limit=limit,
|
||
desc=desc,
|
||
order=order,
|
||
created_after_datetime=created_after_datetime,
|
||
created_before_datetime=created_before_datetime,
|
||
updated_after_datetime=updated_after_datetime,
|
||
updated_before_datetime=updated_before_datetime,
|
||
)
|
||
|
||
|
||
TableViewRequestDep: TypeAlias = Annotated[TableViewRequest, Depends(_get_table_view_queries)]
|
||
"""获取分页排序和时间筛选参数的依赖"""
|
||
|
||
|
||
# --- 用户筛选依赖 ---
|
||
|
||
async def _get_user_filter_params(
|
||
group_id: Annotated[UUID | None, Query(description="按用户组UUID筛选")] = None,
|
||
email: Annotated[str | None, Query(max_length=50, description="按邮箱模糊搜索")] = None,
|
||
nickname: Annotated[str | None, Query(max_length=50, description="按昵称模糊搜索")] = None,
|
||
status: Annotated[UserStatus | None, Query(description="按用户状态筛选")] = None,
|
||
) -> UserFilterParams:
|
||
"""解析用户过滤查询参数"""
|
||
return UserFilterParams(
|
||
group_id=group_id,
|
||
email_contains=email,
|
||
nickname_contains=nickname,
|
||
status=status,
|
||
)
|
||
|
||
|
||
UserFilterParamsDep: TypeAlias = Annotated[UserFilterParams, Depends(_get_user_filter_params)]
|
||
"""获取用户筛选参数的依赖(用于管理员用户列表)"""
|
||
|
||
|
||
# --- 验证码校验依赖 ---
|
||
|
||
def require_captcha(scene: 'CaptchaScene') -> Callable[..., Awaitable[None]]:
|
||
"""
|
||
验证码校验依赖注入工厂。
|
||
|
||
根据场景查询数据库设置,判断是否需要验证码。
|
||
需要则校验前端提交的 captcha_code,失败则抛出异常。
|
||
|
||
使用方式::
|
||
|
||
@router.post('/session', dependencies=[Depends(require_captcha(CaptchaScene.LOGIN))])
|
||
async def login(...): ...
|
||
|
||
:param scene: 验证码使用场景(LOGIN / REGISTER / FORGET)
|
||
"""
|
||
from service.captcha import CaptchaScene, verify_captcha_if_needed
|
||
|
||
async def _verify_captcha(
|
||
session: SessionDep,
|
||
captcha_code: Annotated[str | None, Form()] = None,
|
||
) -> None:
|
||
await verify_captcha_if_needed(session, scene, captcha_code)
|
||
|
||
return _verify_captcha
|