feat: Implement file download token management and restructure file routes
- Added DownloadTokenManager for creating and verifying JWT download tokens. - Introduced new download routes for creating download tokens and downloading files using tokens. - Restructured file upload routes into a dedicated sub-router. - Updated file upload session management with improved error handling and response structures. - Created a new MCP (Microservice Communication Protocol) router with basic request and response models. - Added base models for MCP requests and responses, including method enumeration.
This commit is contained in:
@@ -8,6 +8,10 @@ from .user import (
|
||||
UserResponse,
|
||||
UserSettingResponse,
|
||||
WebAuthnInfo,
|
||||
# 管理员DTO
|
||||
UserAdminUpdateRequest,
|
||||
UserCalibrateResponse,
|
||||
UserAdminDetailResponse,
|
||||
)
|
||||
from .user_authn import AuthnResponse, UserAuthn
|
||||
from .color import ThemeResponse
|
||||
@@ -27,7 +31,11 @@ from .node import (
|
||||
NodeStatus,
|
||||
NodeType,
|
||||
)
|
||||
from .group import Group, GroupBase, GroupOptions, GroupOptionsBase, GroupResponse
|
||||
from .group import (
|
||||
Group, GroupBase, GroupOptions, GroupOptionsBase, GroupResponse,
|
||||
# 管理员DTO
|
||||
GroupCreateRequest, GroupUpdateRequest, GroupDetailResponse, GroupListResponse,
|
||||
)
|
||||
from .object import (
|
||||
CreateFileRequest,
|
||||
CreateUploadSessionRequest,
|
||||
@@ -50,13 +58,21 @@ from .object import (
|
||||
UploadSession,
|
||||
UploadSessionBase,
|
||||
UploadSessionResponse,
|
||||
# 管理员DTO
|
||||
AdminFileResponse,
|
||||
AdminFileListResponse,
|
||||
FileBanRequest,
|
||||
)
|
||||
from .physical_file import PhysicalFile, PhysicalFileBase
|
||||
from .order import Order, OrderStatus, OrderType
|
||||
from .policy import Policy, PolicyOptions, PolicyOptionsBase, PolicyType
|
||||
from .redeem import Redeem, RedeemType
|
||||
from .report import Report, ReportReason
|
||||
from .setting import Setting, SettingsType, SiteConfigResponse
|
||||
from .setting import (
|
||||
Setting, SettingsType, SiteConfigResponse,
|
||||
# 管理员DTO
|
||||
SettingItem, SettingsUpdateRequest, SettingsGetResponse,
|
||||
)
|
||||
from .share import Share
|
||||
from .source_link import SourceLink
|
||||
from .storage_pack import StoragePack
|
||||
@@ -66,13 +82,10 @@ from .webdav import WebDAV
|
||||
|
||||
from .database import engine, get_session
|
||||
|
||||
|
||||
import uuid
|
||||
from sqlmodel import Field
|
||||
from .base import SQLModelBase
|
||||
|
||||
class ResponseBase(SQLModelBase):
|
||||
"""通用响应模型"""
|
||||
|
||||
instance_id: uuid.UUID = Field(default_factory=uuid.uuid4)
|
||||
"""实例ID,用于标识请求的唯一性"""
|
||||
from .model_base import (
|
||||
MCPBase,
|
||||
MCPMethod,
|
||||
MCPRequestBase,
|
||||
MCPResponseBase,
|
||||
ResponseBase,
|
||||
)
|
||||
145
models/group.py
145
models/group.py
@@ -45,6 +45,151 @@ class GroupOptionsBase(SQLModelBase):
|
||||
|
||||
# ==================== DTO 模型 ====================
|
||||
|
||||
class GroupCreateRequest(SQLModelBase):
|
||||
"""创建用户组请求 DTO"""
|
||||
|
||||
name: str = Field(max_length=255)
|
||||
"""用户组名称"""
|
||||
|
||||
max_storage: int = Field(default=0, ge=0)
|
||||
"""最大存储空间(字节),0表示不限制"""
|
||||
|
||||
share_enabled: bool = False
|
||||
"""是否允许创建分享"""
|
||||
|
||||
web_dav_enabled: bool = False
|
||||
"""是否允许使用WebDAV"""
|
||||
|
||||
speed_limit: int = Field(default=0, ge=0)
|
||||
"""速度限制 (KB/s), 0为不限制"""
|
||||
|
||||
# 用户组选项
|
||||
share_download: bool = False
|
||||
"""是否允许分享下载"""
|
||||
|
||||
share_free: bool = False
|
||||
"""是否免积分获取需要积分的内容"""
|
||||
|
||||
relocate: bool = False
|
||||
"""是否允许文件重定位"""
|
||||
|
||||
source_batch: int = Field(default=0, ge=0)
|
||||
"""批量获取源地址数量"""
|
||||
|
||||
select_node: bool = False
|
||||
"""是否允许选择节点"""
|
||||
|
||||
advance_delete: bool = False
|
||||
"""是否允许高级删除"""
|
||||
|
||||
archive_download: bool = False
|
||||
"""是否允许打包下载"""
|
||||
|
||||
archive_task: bool = False
|
||||
"""是否允许创建打包任务"""
|
||||
|
||||
webdav_proxy: bool = False
|
||||
"""是否允许WebDAV代理"""
|
||||
|
||||
aria2: bool = False
|
||||
"""是否允许使用aria2"""
|
||||
|
||||
redirected_source: bool = False
|
||||
"""是否使用重定向源"""
|
||||
|
||||
policy_ids: list[UUID] = []
|
||||
"""关联的存储策略UUID列表"""
|
||||
|
||||
|
||||
class GroupUpdateRequest(SQLModelBase):
|
||||
"""更新用户组请求 DTO(所有字段可选)"""
|
||||
|
||||
name: str | None = Field(default=None, max_length=255)
|
||||
"""用户组名称"""
|
||||
|
||||
max_storage: int | None = Field(default=None, ge=0)
|
||||
"""最大存储空间(字节)"""
|
||||
|
||||
share_enabled: bool | None = None
|
||||
"""是否允许创建分享"""
|
||||
|
||||
web_dav_enabled: bool | None = None
|
||||
"""是否允许使用WebDAV"""
|
||||
|
||||
speed_limit: int | None = Field(default=None, ge=0)
|
||||
"""速度限制 (KB/s)"""
|
||||
|
||||
# 用户组选项
|
||||
share_download: bool | None = None
|
||||
share_free: bool | None = None
|
||||
relocate: bool | None = None
|
||||
source_batch: int | None = None
|
||||
select_node: bool | None = None
|
||||
advance_delete: bool | None = None
|
||||
archive_download: bool | None = None
|
||||
archive_task: bool | None = None
|
||||
webdav_proxy: bool | None = None
|
||||
aria2: bool | None = None
|
||||
redirected_source: bool | None = None
|
||||
|
||||
policy_ids: list[UUID] | None = None
|
||||
"""关联的存储策略UUID列表"""
|
||||
|
||||
|
||||
class GroupDetailResponse(SQLModelBase):
|
||||
"""用户组详情响应 DTO"""
|
||||
|
||||
id: UUID
|
||||
"""用户组UUID"""
|
||||
|
||||
name: str
|
||||
"""用户组名称"""
|
||||
|
||||
max_storage: int = 0
|
||||
"""最大存储空间(字节)"""
|
||||
|
||||
share_enabled: bool = False
|
||||
"""是否允许创建分享"""
|
||||
|
||||
web_dav_enabled: bool = False
|
||||
"""是否允许使用WebDAV"""
|
||||
|
||||
admin: bool = False
|
||||
"""是否为管理员组"""
|
||||
|
||||
speed_limit: int = 0
|
||||
"""速度限制 (KB/s)"""
|
||||
|
||||
user_count: int = 0
|
||||
"""用户数量"""
|
||||
|
||||
policy_ids: list[UUID] = []
|
||||
"""关联的存储策略UUID列表"""
|
||||
|
||||
# 选项
|
||||
share_download: bool = False
|
||||
share_free: bool = False
|
||||
relocate: bool = False
|
||||
source_batch: int = 0
|
||||
select_node: bool = False
|
||||
advance_delete: bool = False
|
||||
archive_download: bool = False
|
||||
archive_task: bool = False
|
||||
webdav_proxy: bool = False
|
||||
aria2: bool = False
|
||||
redirected_source: bool = False
|
||||
|
||||
|
||||
class GroupListResponse(SQLModelBase):
|
||||
"""用户组列表响应 DTO"""
|
||||
|
||||
groups: list["GroupDetailResponse"] = []
|
||||
"""用户组列表"""
|
||||
|
||||
total: int = 0
|
||||
"""总数"""
|
||||
|
||||
|
||||
class GroupResponse(GroupBase, GroupOptionsBase):
|
||||
"""用户组响应 DTO"""
|
||||
|
||||
|
||||
39
models/model_base.py
Normal file
39
models/model_base.py
Normal file
@@ -0,0 +1,39 @@
|
||||
import uuid
|
||||
from enum import StrEnum
|
||||
|
||||
from sqlmodel import Field
|
||||
|
||||
from .base import SQLModelBase
|
||||
|
||||
class MCPMethod(StrEnum):
|
||||
"""MCP 方法枚举"""
|
||||
|
||||
PING = "ping"
|
||||
"""Ping 方法,用于测试连接"""
|
||||
|
||||
class MCPBase(SQLModelBase):
|
||||
"""MCP 请求基础模型"""
|
||||
|
||||
jsonrpc: str = "2.0"
|
||||
"""JSON-RPC 版本"""
|
||||
|
||||
id: uuid.UUID = Field(default_factory=uuid.uuid4)
|
||||
"""请求/响应 ID,用于标识请求/响应的唯一性"""
|
||||
|
||||
class MCPRequestBase(MCPBase):
|
||||
"""MCP 请求模型基础类"""
|
||||
|
||||
method: str
|
||||
"""方法名称"""
|
||||
|
||||
class MCPResponseBase(MCPBase):
|
||||
"""MCP 响应模型基础类"""
|
||||
|
||||
result: str
|
||||
"""方法返回结果"""
|
||||
|
||||
class ResponseBase(SQLModelBase):
|
||||
"""通用响应模型"""
|
||||
|
||||
instance_id: uuid.UUID = Field(default_factory=uuid.uuid4)
|
||||
"""实例ID,用于标识请求的唯一性"""
|
||||
@@ -4,7 +4,7 @@ from typing import TYPE_CHECKING, Literal
|
||||
from uuid import UUID
|
||||
|
||||
from enum import StrEnum
|
||||
from sqlmodel import Field, Relationship, UniqueConstraint, CheckConstraint, Index
|
||||
from sqlmodel import Field, Relationship, UniqueConstraint, CheckConstraint, Index, text
|
||||
|
||||
from .base import SQLModelBase
|
||||
from .mixin import UUIDTableBaseMixin
|
||||
@@ -258,11 +258,39 @@ class Object(ObjectBase, UUIDTableBaseMixin):
|
||||
)
|
||||
"""存储策略UUID(文件直接使用,目录作为子文件的默认策略)"""
|
||||
|
||||
# ==================== 封禁相关字段 ====================
|
||||
|
||||
is_banned: bool = Field(default=False, sa_column_kwargs={"server_default": text("false")})
|
||||
"""是否被封禁"""
|
||||
|
||||
banned_at: datetime | None = None
|
||||
"""封禁时间"""
|
||||
|
||||
banned_by: UUID | None = Field(
|
||||
default=None,
|
||||
foreign_key="user.id",
|
||||
index=True,
|
||||
ondelete="SET NULL",
|
||||
sa_column_kwargs={"name": "banned_by"}
|
||||
)
|
||||
"""封禁操作者UUID"""
|
||||
|
||||
ban_reason: str | None = Field(default=None, max_length=500)
|
||||
"""封禁原因"""
|
||||
|
||||
# ==================== 关系 ====================
|
||||
|
||||
owner: "User" = Relationship(back_populates="objects")
|
||||
owner: "User" = Relationship(
|
||||
back_populates="objects",
|
||||
sa_relationship_kwargs={"foreign_keys": "[Object.owner_id]"}
|
||||
)
|
||||
"""所有者"""
|
||||
|
||||
banner: "User" = Relationship(
|
||||
sa_relationship_kwargs={"foreign_keys": "[Object.banned_by]"}
|
||||
)
|
||||
"""封禁操作者"""
|
||||
|
||||
policy: "Policy" = Relationship(back_populates="objects")
|
||||
"""存储策略"""
|
||||
|
||||
@@ -642,3 +670,47 @@ class ObjectPropertyDetailResponse(ObjectPropertyResponse):
|
||||
|
||||
reference_count: int = 1
|
||||
"""物理文件引用计数(仅文件有效)"""
|
||||
|
||||
|
||||
# ==================== 管理员文件管理 DTO ====================
|
||||
|
||||
class AdminFileResponse(ObjectResponse):
|
||||
"""管理员文件响应 DTO"""
|
||||
|
||||
owner_id: UUID
|
||||
"""所有者UUID"""
|
||||
|
||||
owner_username: str
|
||||
"""所有者用户名"""
|
||||
|
||||
policy_name: str
|
||||
"""存储策略名称"""
|
||||
|
||||
is_banned: bool = False
|
||||
"""是否被封禁"""
|
||||
|
||||
banned_at: datetime | None = None
|
||||
"""封禁时间"""
|
||||
|
||||
ban_reason: str | None = None
|
||||
"""封禁原因"""
|
||||
|
||||
|
||||
class FileBanRequest(SQLModelBase):
|
||||
"""文件封禁请求 DTO"""
|
||||
|
||||
is_banned: bool = True
|
||||
"""是否封禁"""
|
||||
|
||||
reason: str | None = Field(default=None, max_length=500)
|
||||
"""封禁原因"""
|
||||
|
||||
|
||||
class AdminFileListResponse(SQLModelBase):
|
||||
"""管理员文件列表响应 DTO"""
|
||||
|
||||
files: list[AdminFileResponse] = []
|
||||
"""文件列表"""
|
||||
|
||||
total: int = 0
|
||||
"""总数"""
|
||||
|
||||
@@ -40,6 +40,32 @@ class SiteConfigResponse(SQLModelBase):
|
||||
"""验证码密钥"""
|
||||
|
||||
|
||||
# ==================== 管理员设置 DTO ====================
|
||||
|
||||
class SettingItem(SQLModelBase):
|
||||
"""设置项 DTO"""
|
||||
|
||||
name: str
|
||||
"""设置项名称"""
|
||||
|
||||
value: str | None = None
|
||||
"""设置值"""
|
||||
|
||||
|
||||
class SettingsUpdateRequest(SQLModelBase):
|
||||
"""更新设置请求 DTO"""
|
||||
|
||||
settings: dict[str, dict[str, str | None]]
|
||||
"""按类型分组的设置项,格式: {"basic": {"siteName": "xxx", ...}, ...}"""
|
||||
|
||||
|
||||
class SettingsGetResponse(SQLModelBase):
|
||||
"""获取设置响应 DTO"""
|
||||
|
||||
settings: dict[str, dict[str, str | None]] = {}
|
||||
"""按类型分组的设置项"""
|
||||
|
||||
|
||||
# ==================== 数据库模型 ====================
|
||||
|
||||
class SettingsType(StrEnum):
|
||||
|
||||
@@ -201,6 +201,68 @@ class UserSettingResponse(SQLModelBase):
|
||||
"""用户UUID"""
|
||||
|
||||
|
||||
# ==================== 管理员用户管理 DTO ====================
|
||||
|
||||
class UserAdminUpdateRequest(SQLModelBase):
|
||||
"""管理员更新用户请求 DTO"""
|
||||
|
||||
nickname: str | None = Field(default=None, max_length=50)
|
||||
"""昵称"""
|
||||
|
||||
password: str | None = None
|
||||
"""新密码(为空则不修改)"""
|
||||
|
||||
group_id: UUID | None = None
|
||||
"""用户组UUID"""
|
||||
|
||||
status: bool | None = None
|
||||
"""用户状态"""
|
||||
|
||||
score: int | None = Field(default=None, ge=0)
|
||||
"""积分"""
|
||||
|
||||
storage: int | None = Field(default=None, ge=0)
|
||||
"""已用存储空间(用于手动校准)"""
|
||||
|
||||
group_expires: datetime | None = None
|
||||
"""用户组过期时间"""
|
||||
|
||||
|
||||
class UserCalibrateResponse(SQLModelBase):
|
||||
"""用户存储校准响应 DTO"""
|
||||
|
||||
user_id: UUID
|
||||
"""用户UUID"""
|
||||
|
||||
previous_storage: int
|
||||
"""校准前的存储空间(字节)"""
|
||||
|
||||
current_storage: int
|
||||
"""校准后的存储空间(字节)"""
|
||||
|
||||
difference: int
|
||||
"""差异值(字节)"""
|
||||
|
||||
file_count: int
|
||||
"""实际文件数量"""
|
||||
|
||||
|
||||
class UserAdminDetailResponse(UserPublic):
|
||||
"""管理员用户详情响应 DTO"""
|
||||
|
||||
two_factor_enabled: bool = False
|
||||
"""是否启用两步验证"""
|
||||
|
||||
file_count: int = 0
|
||||
"""文件数量"""
|
||||
|
||||
share_count: int = 0
|
||||
"""分享数量"""
|
||||
|
||||
task_count: int = 0
|
||||
"""任务数量"""
|
||||
|
||||
|
||||
# 前向引用导入
|
||||
from .group import GroupResponse # noqa: E402
|
||||
from .user_authn import AuthnResponse # noqa: E402
|
||||
|
||||
Reference in New Issue
Block a user