feat: migrate ORM base to sqlmodel-ext, add file viewers and WOPI integration
All checks were successful
Test / test (push) Successful in 1m45s
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>
This commit is contained in:
106
routers/api/v1/file/viewers/__init__.py
Normal file
106
routers/api/v1/file/viewers/__init__.py
Normal file
@@ -0,0 +1,106 @@
|
||||
"""
|
||||
文件查看器查询端点
|
||||
|
||||
提供按文件扩展名查询可用查看器的功能,包含用户组访问控制过滤。
|
||||
"""
|
||||
from typing import Annotated
|
||||
from uuid import UUID
|
||||
|
||||
from fastapi import APIRouter, Depends, Query
|
||||
from sqlalchemy import and_
|
||||
|
||||
from sqlalchemy import select
|
||||
|
||||
from middleware.auth import auth_required
|
||||
from middleware.dependencies import SessionDep
|
||||
from sqlmodels import (
|
||||
FileApp,
|
||||
FileAppExtension,
|
||||
FileAppGroupLink,
|
||||
FileAppSummary,
|
||||
FileViewersResponse,
|
||||
User,
|
||||
UserFileAppDefault,
|
||||
)
|
||||
|
||||
viewers_router = APIRouter(prefix="/viewers", tags=["file", "viewers"])
|
||||
|
||||
|
||||
@viewers_router.get(
|
||||
path='',
|
||||
summary='查询可用文件查看器',
|
||||
description='根据文件扩展名查询可用的查看器应用列表。',
|
||||
)
|
||||
async def get_viewers(
|
||||
session: SessionDep,
|
||||
user: Annotated[User, Depends(auth_required)],
|
||||
ext: Annotated[str, Query(max_length=20, description="文件扩展名")],
|
||||
) -> FileViewersResponse:
|
||||
"""
|
||||
查询可用文件查看器端点
|
||||
|
||||
流程:
|
||||
1. 规范化扩展名(小写,去点号)
|
||||
2. 查询匹配的已启用应用
|
||||
3. 按用户组权限过滤
|
||||
4. 按 priority 排序
|
||||
5. 查询用户默认偏好
|
||||
|
||||
认证:JWT token 必填
|
||||
|
||||
错误处理:
|
||||
- 401: 未授权
|
||||
"""
|
||||
# 规范化扩展名
|
||||
normalized_ext = ext.lower().strip().lstrip('.')
|
||||
|
||||
# 查询匹配扩展名的应用(已启用的)
|
||||
ext_records: list[FileAppExtension] = await FileAppExtension.get(
|
||||
session,
|
||||
and_(
|
||||
FileAppExtension.extension == normalized_ext,
|
||||
),
|
||||
fetch_mode="all",
|
||||
load=FileAppExtension.app,
|
||||
)
|
||||
|
||||
# 过滤和收集可用应用
|
||||
user_group_id = user.group_id
|
||||
viewers: list[tuple[FileAppSummary, int]] = []
|
||||
|
||||
for ext_record in ext_records:
|
||||
app: FileApp = ext_record.app
|
||||
if not app.is_enabled:
|
||||
continue
|
||||
|
||||
if app.is_restricted:
|
||||
# 检查用户组权限(FileAppGroupLink 是纯关联表,使用 session 查询)
|
||||
stmt = select(FileAppGroupLink).where(
|
||||
and_(
|
||||
FileAppGroupLink.app_id == app.id,
|
||||
FileAppGroupLink.group_id == user_group_id,
|
||||
)
|
||||
)
|
||||
result = await session.exec(stmt)
|
||||
group_link = result.first()
|
||||
if not group_link:
|
||||
continue
|
||||
|
||||
viewers.append((app.to_summary(), ext_record.priority))
|
||||
|
||||
# 按 priority 排序
|
||||
viewers.sort(key=lambda x: x[1])
|
||||
|
||||
# 查询用户默认偏好
|
||||
user_default: UserFileAppDefault | None = await UserFileAppDefault.get(
|
||||
session,
|
||||
and_(
|
||||
UserFileAppDefault.user_id == user.id,
|
||||
UserFileAppDefault.extension == normalized_ext,
|
||||
),
|
||||
)
|
||||
|
||||
return FileViewersResponse(
|
||||
viewers=[v[0] for v in viewers],
|
||||
default_viewer_id=user_default.app_id if user_default else None,
|
||||
)
|
||||
Reference in New Issue
Block a user