From 6c3a6012599fdc9b821a9cd1d7b3e4b8a6470230 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BA=8E=E5=B0=8F=E4=B8=98?= Date: Fri, 19 Dec 2025 20:18:36 +0800 Subject: [PATCH] Refactor GroupOptions model and update documentation - Removed the `available_nodes` field from the GroupOptions model in `group.py`. - Updated imports in `pwd.py` by removing unused imports. - Added a comprehensive roadmap document outlining the development stages and features for DiskNext Server. - Created a detailed README for the models directory, documenting the database models and their relationships. --- README.md | 218 +++++++++++-- ROADMAP.md | 275 ++++++++++++++++ models/README.md | 733 ++++++++++++++++++++++++++++++++++++++++++ models/group.py | 3 - utils/password/pwd.py | 2 +- 5 files changed, 1208 insertions(+), 23 deletions(-) create mode 100644 ROADMAP.md create mode 100644 models/README.md diff --git a/README.md b/README.md index c56e934..62e2cee 100644 --- a/README.md +++ b/README.md @@ -4,33 +4,213 @@
-

支持多家云存储的公私兼备的云服务系统.

+

支持多家云存储的公私兼备的云服务系统后端

-本来此项目并没有这么快开始,但由于我曾经使用过的某个类似产品的作者吃相实在难看,故决定自己实现一个。 +

+ Python + FastAPI + SQLModel + License + Status +

-此项目的愿景是集百家之长(Cloudreve + Alist + FnOS + KodBox)。你也可以考虑付费支持我们的发展 -> `DiskNext Pro`. +--- -目前正处于 `OMEGA` 实验阶段,比 `Alpha` 版还更早期,仅供测试。 +本项目旨在集百家之长(Cloudreve + Alist/OpenList + FnOS + KodBox),打造一个功能强大、安全可靠的云存储解决方案。 + +> **注意**:目前正处于 `OMEGA` 实验阶段,比 `Alpha` 版还更早期,仅供测试和开发。 ## 特性 -- 支持将文件存储到本地、远程节点、OneDrive 以及 S3兼容API、阿里云OSS等 -- 内置离线下载服务,亦可对接Aria2/qBittorrent 下载文件,可用多个节点分担下载任务 -- 在线压缩/解压缩文件,支持批量下载 -- 部署方便,开箱即用,亦可通过配置获得强大的生态能力 -- 可信、现代化的安全能力(JWT令牌、OAuth2、WebAuthn、全盘加密) -- 兼容 WebDAV、Subsonic 接口 -- 支持多用户、多群组,分级管理权限俱全 -- 强大的分享链接管理,支持分享页README渲染、媒体元数据展示 -- 在线预览/编辑多种文件,包括但不限于视频、图片、音频、PDF、ePub、Office、Markdown、图表等 -- 自定义主题色、深浅色主题、PWA、i18n +### 存储能力 -## ⚗️ 技术栈 +- **多存储策略**:支持本地存储、S3 兼容 API、阿里云 OSS、OneDrive 等多种存储后端 +- **远程节点**:可对接从节点分担存储和下载任务 +- **WebDAV 兼容**:提供标准 WebDAV 接口,支持第三方客户端访问 -* [Python](https://www.python.org/) + [FastAPI](https://fastapi.tiangolo.com/) +### 文件管理 - +- **统一对象模型**:文件和目录采用统一的 Object 模型管理 +- **在线压缩/解压**:支持批量打包下载 +- **离线下载**:内置离线下载服务,也可对接 Aria2/qBittorrent -## 📜 许可证 +### 用户与权限 -GPL V3 +- **多用户系统**:支持用户注册、登录、个人设置 +- **用户组管理**:灵活的分级权限控制 +- **存储配额**:可为用户组设置存储空间限制 + +### 安全能力 + +- **JWT 令牌认证**:基于 OAuth2.1 规范的安全认证 +- **两步验证 (2FA)**:支持 TOTP 两步验证 +- **WebAuthn**:支持 Passkey 无密码登录 +- **OAuth 登录**:支持 QQ、GitHub 等第三方登录 + +### 分享功能 + +- **分享链接管理**:可设置密码、过期时间 +- **分享页展示**:支持 README 渲染、媒体元数据展示 + +### 增值服务 + +- **积分系统**:支持用户积分管理 +- **兑换码**:支持兑换码功能 +- **容量包**:可购买额外存储空间 + +## 技术栈 + +### 后端 + +| 技术 | 说明 | +|------|------| +| [Python 3.13+](https://www.python.org/) | 编程语言 | +| [FastAPI](https://fastapi.tiangolo.com/) | 高性能异步 Web 框架 | +| [SQLModel](https://sqlmodel.tiangolo.com/) | 类型安全的 ORM(SQLAlchemy + Pydantic) | +| [aiohttp](https://docs.aiohttp.org/) | 异步 HTTP 客户端 | +| [aiosqlite](https://aiosqlite.omnilib.dev/) | 异步 SQLite 驱动 | +| [Loguru](https://loguru.readthedocs.io/) | 现代化日志库 | +| [PyJWT](https://pyjwt.readthedocs.io/) | JWT 令牌处理 | +| [WebAuthn](https://pypi.org/project/webauthn/) | Passkey 认证支持 | +| [Argon2](https://argon2-cffi.readthedocs.io/) | 安全密码哈希 | +| [pytest](https://pytest.org/) | 测试框架 | + +## 项目结构 + +``` +Server/ +├── main.py # 应用入口 +├── models/ # 数据模型 +│ ├── base/ # 基类定义 (SQLModelBase, TableBase) +│ ├── user.py # 用户模型 +│ ├── group.py # 用户组模型 +│ ├── object.py # 文件/目录统一模型 +│ ├── policy.py # 存储策略模型 +│ ├── share.py # 分享模型 +│ └── ... +├── routers/ # API 路由 +│ └── api/v1/ # v1 版本 API +│ ├── user/ # 用户相关接口 +│ ├── directory/ # 目录相关接口 +│ ├── file/ # 文件相关接口 +│ ├── admin/ # 管理员接口 +│ └── ... +├── service/ # 业务服务层 +│ ├── user/ # 用户服务 +│ ├── captcha/ # 验证码服务 +│ └── oauth/ # OAuth 服务 +├── middleware/ # 中间件 +│ ├── auth.py # 认证中间件 +│ └── dependencies.py # 依赖注入 +├── utils/ # 工具函数 +│ ├── JWT/ # JWT 处理 +│ ├── password/ # 密码处理 +│ ├── conf/ # 配置管理 +│ └── lifespan/ # 生命周期管理 +└── tests/ # 测试用例 + ├── unit/ # 单元测试 + ├── integration/ # 集成测试 + └── fixtures/ # 测试夹具 +``` + +## API 概览 + +| 模块 | 前缀 | 说明 | +|------|------|------| +| 站点 | `/api/v1/site` | 站点配置和公开信息 | +| 用户 | `/api/v1/user` | 用户注册、登录、设置 | +| 目录 | `/api/v1/directory` | 目录浏览和管理 | +| 文件 | `/api/v1/file` | 文件上传、下载、管理 | +| 对象 | `/api/v1/object` | 文件和目录的通用操作 | +| 分享 | `/api/v1/share` | 分享链接管理 | +| 下载 | `/api/v1/download` | 离线下载管理 | +| 标签 | `/api/v1/tag` | 用户标签管理 | +| WebDAV | `/api/v1/webdav` | WebDAV 账号管理 | +| 增值服务 | `/api/v1/vas` | 积分、兑换码等 | +| 回调 | `/api/v1/callback` | 第三方回调接口 | +| 从节点 | `/api/v1/slave` | 从节点通信接口 | +| 管理员 | `/api/v1/admin/*` | 后台管理接口 | + +## 快速开始 + +### 环境要求 + +- Python 3.13 或更高版本 +- uv (推荐) 或 pip + +### 安装 + +```bash +# 克隆项目 +git clone https://github.com/yourusername/DiskNext-Server.git +cd DiskNext-Server + +# 使用 uv 安装依赖 +uv sync +``` + +### 配置 + +创建 `.env` 文件配置环境变量: + +```env +# 调试模式 +DEBUG=false + +# 数据库连接(默认使用 SQLite) +DATABASE_URL=sqlite+aiosqlite:///disknext.db +``` + +### 启动 + +```bash +# 开发模式 +fastapi dev main:app + +# 生产模式 +fastapi run main:app +``` + +访问 http://localhost:8000/docs 查看 API 文档。 + +## 测试 + +```bash +# 运行所有测试 +pytest + +# 运行单元测试 +pytest tests/unit + +# 运行集成测试 +pytest tests/integration + +# 生成覆盖率报告 +pytest --cov +``` + +## 开发规范 + +详细的开发规范请参阅 [CLAUDE.md](CLAUDE.md),主要包括: + +- 类型安全与显式优于隐式 +- 异步优先,IO 绝不阻塞 +- 单一真相来源原则 +- 目录结构即 API 结构 +- SQLModel 使用规范 + +## 路线图 + +查看 [ROADMAP.md](ROADMAP.md) 了解项目开发计划。 + +## 贡献 + +欢迎提交 Issue 和 Pull Request! + +## 许可证 + +本项目采用 [GPL v3](https://opensource.org/license/gpl-3.0) 许可证。 + +--- + +> 你也可以考虑付费支持我们的发展 -> `DiskNext Pro` diff --git a/ROADMAP.md b/ROADMAP.md new file mode 100644 index 0000000..7f1ba2e --- /dev/null +++ b/ROADMAP.md @@ -0,0 +1,275 @@ +# DiskNext Server 开发路线图 + +本文档概述 DiskNext Server 的开发计划和进度。项目当前处于 **OMEGA** 实验阶段。 + +--- + +## 版本规划 + +| 阶段 | 版本 | 状态 | 说明 | +|------|------|------|------| +| OMEGA | 0.0.x | **当前** | 实验性开发,API 可能频繁变动 | +| Alpha | 0.1.x | 计划中 | 核心功能基本可用 | +| Beta | 0.5.x | 计划中 | 功能完善,开始公测 | +| RC | 0.9.x | 计划中 | 候选发布版本 | +| Stable | 1.0.0 | 计划中 | 正式稳定版本 | + +--- + +## OMEGA 阶段 (v0.0.x) - 当前 + +### 已完成 + +#### 基础架构 +- [x] FastAPI 应用框架搭建 +- [x] SQLModel ORM 集成 +- [x] 异步数据库支持 (aiosqlite) +- [x] 项目结构规范化 +- [x] 开发规范文档 (CLAUDE.md) + +#### 数据模型 +- [x] 基类定义 (SQLModelBase, TableBase, UUIDTableBase) +- [x] 用户模型 (User) +- [x] 用户组模型 (Group, GroupOptions) +- [x] 统一对象模型 (Object) - 合并文件和目录 +- [x] 存储策略模型 (Policy) +- [x] 分享模型 (Share) +- [x] 标签模型 (Tag) +- [x] WebDAV 模型 (WebDAV) +- [x] 设置模型 (Setting) +- [x] 其他模型 (Order, Redeem, Report, Task, SourceLink, StoragePack, Download, Node) + +#### 用户系统 +- [x] 用户注册接口 +- [x] 用户登录接口 (OAuth2.1 Password Grant) +- [x] JWT 令牌认证 +- [x] 获取当前用户信息 +- [x] 用户存储空间查询 + +#### 认证安全 +- [x] Argon2 密码哈希 +- [x] JWT 令牌生成与验证 +- [x] 认证中间件 +- [x] 两步验证 (2FA/TOTP) 初始化与启用 +- [x] WebAuthn 注册初始化 + +#### 测试 +- [x] pytest 测试框架配置 +- [x] 单元测试结构 +- [x] 集成测试结构 +- [x] 测试夹具 (fixtures) + +### 进行中 + +#### 用户系统 +- [ ] WebAuthn 完整流程 +- [ ] OAuth 第三方登录 (QQ, GitHub) +- [ ] 用户设置管理 +- [ ] 头像上传/Gravatar + +#### 目录系统 +- [ ] 目录浏览接口 +- [ ] 目录创建接口 +- [ ] 路径解析优化 + +#### 存储策略 +- [ ] 本地存储策略实现 +- [ ] S3 存储策略实现 + +--- + +## Alpha 阶段 (v0.1.x) - 计划中 + +### 文件操作 + +- [ ] 文件上传(单文件) +- [ ] 文件上传(分块上传) +- [ ] 文件下载 +- [ ] 文件预览 URL 生成 +- [ ] 缩略图生成 +- [ ] 文件移动/复制 +- [ ] 文件重命名 +- [ ] 文件删除(软删除/回收站) + +### 目录操作 + +- [ ] 目录树查询 +- [ ] 目录移动/复制 +- [ ] 目录删除(递归) +- [ ] 批量操作 + +### 存储策略完善 + +- [ ] 阿里云 OSS 支持 +- [ ] 腾讯云 COS 支持 +- [ ] 七牛云支持 +- [ ] OneDrive 支持 +- [ ] 存储策略切换 + +### 用户组权限 + +- [ ] 权限验证中间件 +- [ ] 存储空间限制 +- [ ] 文件类型限制 +- [ ] 单文件大小限制 + +--- + +## Beta 阶段 (v0.5.x) - 计划中 + +### 分享功能 + +- [ ] 创建分享链接 +- [ ] 分享密码保护 +- [ ] 分享过期时间 +- [ ] 分享访问统计 +- [ ] 分享页面数据接口 + +### 离线下载 + +- [ ] Aria2 RPC 集成 +- [ ] qBittorrent API 集成 +- [ ] 下载任务管理 +- [ ] 下载完成回调 + +### WebDAV + +- [ ] WebDAV 账号管理 +- [ ] WebDAV 协议实现 +- [ ] WebDAV 代理功能 + +### 增值服务 + +- [ ] 积分系统实现 +- [ ] 兑换码生成与使用 +- [ ] 存储容量包 +- [ ] 订单管理 + +### 管理后台 + +- [ ] 用户管理接口 +- [ ] 用户组管理接口 +- [ ] 存储策略管理接口 +- [ ] 系统设置接口 +- [ ] 任务管理接口 +- [ ] 文件管理接口 +- [ ] 数据统计接口 + +--- + +## RC 阶段 (v0.9.x) - 计划中 + +### 分布式支持 + +- [ ] 从节点注册与认证 +- [ ] 从节点任务分发 +- [ ] 从节点健康检查 +- [ ] 负载均衡 + +### 性能优化 + +- [ ] 数据库查询优化 +- [ ] 缓存层 (Redis) +- [ ] CDN 集成 +- [ ] 并发上传优化 + +### 安全加固 + +- [ ] 速率限制 +- [ ] 安全审计日志 +- [ ] 敏感操作二次验证 +- [ ] CORS 配置优化 + +### 在线预览 + +- [ ] 图片预览 +- [ ] 视频播放 +- [ ] 音频播放 +- [ ] PDF 预览 +- [ ] Office 文档预览 +- [ ] Markdown 渲染 +- [ ] 代码高亮 + +--- + +## Stable 阶段 (v1.0.0) - 计划中 + +### 功能完善 + +- [ ] 全盘搜索 +- [ ] 文件标签 +- [ ] 收藏夹 +- [ ] 最近访问 +- [ ] 回收站 + +### 国际化 + +- [ ] i18n 框架集成 +- [ ] 多语言错误消息 +- [ ] API 文档多语言 + +### 文档完善 + +- [ ] API 文档完善 +- [ ] 部署文档 +- [ ] 开发者文档 +- [ ] 用户手册 + +### 生产就绪 + +- [ ] Docker 镜像 +- [ ] Docker Compose 配置 +- [ ] Kubernetes 部署配置 +- [ ] 监控指标 (Prometheus) +- [ ] 健康检查端点 + +--- + +## 未来展望 (v1.x+) + +### 高级功能 + +- [ ] 文件版本历史 +- [ ] 文件加密存储 +- [ ] 文件同步客户端 API +- [ ] Subsonic 音乐接口 +- [ ] 照片管理(相册、时间线) +- [ ] AI 文件分类与搜索 + +### 企业功能 (Pro) + +- [ ] LDAP/AD 集成 +- [ ] SSO 单点登录 +- [ ] 审计日志 +- [ ] 高级权限控制 +- [ ] 企业工作空间 +- [ ] 协作功能 + +### 生态集成 + +- [ ] Rclone 集成 +- [ ] 备份工具集成 +- [ ] 移动端 API 优化 +- [ ] 桌面客户端支持 + +--- + +## 贡献指南 + +如果你想参与项目开发,可以: + +1. 查看上方的待办事项,选择感兴趣的功能 +2. 在 Issue 中认领任务 +3. 阅读 [CLAUDE.md](CLAUDE.md) 了解开发规范 +4. 提交 Pull Request + +我们特别欢迎以下方面的贡献: + +- 存储策略实现(各类云存储) +- 测试用例编写 +- 文档完善 +- Bug 修复 + +--- + +*最后更新:2025年12月* \ No newline at end of file diff --git a/models/README.md b/models/README.md new file mode 100644 index 0000000..7f43608 --- /dev/null +++ b/models/README.md @@ -0,0 +1,733 @@ +# Models 数据库模型文档 + +本目录包含 DiskNext Server 的所有数据库模型定义,基于 SQLModel 框架实现。 + +## 目录结构 + +``` +models/ +├── base/ # 基础模型类 +│ ├── sqlmodel_base.py # SQLModelBase 基类 +│ └── table_base.py # TableBase 和 UUIDTableBase +├── user.py # 用户模型 +├── user_authn.py # 用户 WebAuthn 凭证 +├── group.py # 用户组模型 +├── policy.py # 存储策略模型 +├── object.py # 统一对象模型(文件/目录) +├── share.py # 分享模型 +├── tag.py # 标签模型 +├── download.py # 离线下载任务 +├── task.py # 任务模型 +├── node.py # 节点模型 +├── order.py # 订单模型 +├── redeem.py # 兑换码模型 +├── report.py # 举报模型 +├── setting.py # 系统设置模型 +├── source_link.py # 源链接模型 +├── storage_pack.py # 容量包模型 +├── webdav.py # WebDAV 账户模型 +├── color.py # 主题颜色 DTO +├── response.py # 响应 DTO +└── database.py # 数据库连接配置 +``` + +--- + +## 基础类 + +### SQLModelBase + +所有模型的基类,配置了: +- `use_attribute_docstrings=True`:使用属性后的 docstring 作为字段描述 +- `validate_by_name=True`:允许按名称验证 + +### TableBase + +数据库表基类,包含以下公共字段: + +| 字段 | 类型 | 说明 | +|------|------|------| +| `id` | `int` | 自增主键 | +| `created_at` | `datetime` | 创建时间 | +| `updated_at` | `datetime` | 更新时间(自动更新) | + +提供的 CRUD 方法: +- `add()` - 新增记录 +- `save()` - 保存实例 +- `update()` - 更新记录 +- `delete()` - 删除记录 +- `get()` - 查询记录 +- `get_exist_one()` - 获取存在的记录(不存在则抛出 404) + +### UUIDTableBase + +继承自 TableBase,将主键改为 UUID 类型: + +| 字段 | 类型 | 说明 | +|------|------|------| +| `id` | `UUID` | UUID 主键(自动生成) | + +--- + +## 数据库表模型 + +### 1. User(用户) + +**表名**: `user` +**基类**: `UUIDTableBase` + +| 字段 | 类型 | 说明 | +|------|------|------| +| `id` | `UUID` | 用户 UUID(主键) | +| `username` | `str` | 用户名,唯一,不可更改 | +| `nickname` | `str?` | 用户昵称 | +| `password` | `str` | 密码(加密后) | +| `status` | `bool` | 用户状态:True=正常,False=封禁 | +| `storage` | `int` | 已用存储空间(字节) | +| `two_factor` | `str?` | 两步验证密钥 | +| `avatar` | `str` | 头像类型/地址 | +| `score` | `int` | 用户积分 | +| `group_expires` | `datetime?` | 当前用户组过期时间 | +| `theme` | `ThemeType` | 主题类型:light/dark/system | +| `language` | `str` | 语言偏好(默认 zh-CN) | +| `timezone` | `int` | 时区 UTC 偏移(-12 ~ 12) | +| `group_id` | `UUID` | 所属用户组(外键) | +| `previous_group_id` | `UUID?` | 之前的用户组(用于过期后恢复) | + +--- + +### 2. UserAuthn(WebAuthn 凭证) + +**表名**: `userauthn` +**基类**: `TableBase` + +| 字段 | 类型 | 说明 | +|------|------|------| +| `id` | `int` | 主键 | +| `credential_id` | `str` | 凭证 ID(Base64 编码) | +| `credential_public_key` | `str` | 凭证公钥(Base64 编码) | +| `sign_count` | `int` | 签名计数器(防重放) | +| `credential_device_type` | `str` | 设备类型:single_device/multi_device | +| `credential_backed_up` | `bool` | 凭证是否已备份 | +| `transports` | `str?` | 支持的传输方式(逗号分隔) | +| `name` | `str?` | 用户自定义凭证名称 | +| `user_id` | `UUID` | 所属用户(外键) | + +--- + +### 3. Group(用户组) + +**表名**: `group` +**基类**: `UUIDTableBase` + +| 字段 | 类型 | 说明 | +|------|------|------| +| `id` | `UUID` | 用户组 UUID(主键) | +| `name` | `str` | 用户组名称,唯一 | +| `max_storage` | `int` | 最大存储空间(字节) | +| `share_enabled` | `bool` | 是否允许创建分享 | +| `web_dav_enabled` | `bool` | 是否允许使用 WebDAV | +| `admin` | `bool` | 是否为管理员组 | +| `speed_limit` | `int` | 速度限制(KB/s),0 为不限制 | + +--- + +### 4. GroupOptions(用户组选项) + +**表名**: `groupoptions` +**基类**: `TableBase` + +| 字段 | 类型 | 说明 | +|------|------|------| +| `id` | `int` | 主键 | +| `group_id` | `UUID` | 关联的用户组(外键,唯一) | +| `share_download` | `bool` | 是否允许分享下载 | +| `share_free` | `bool` | 是否免积分获取内容 | +| `relocate` | `bool` | 是否允许文件重定位 | +| `source_batch` | `int` | 批量获取源地址数量 | +| `select_node` | `bool` | 是否允许选择节点 | +| `advance_delete` | `bool` | 是否允许高级删除 | +| `archive_download` | `bool` | 是否允许打包下载 | +| `archive_task` | `bool` | 是否允许创建打包任务 | +| `webdav_proxy` | `bool` | 是否允许 WebDAV 代理 | +| `aria2` | `bool` | 是否允许使用 aria2 | +| `redirected_source` | `bool` | 是否使用重定向源 | + +--- + +### 5. GroupPolicyLink(用户组-策略关联) + +**表名**: `grouppolicylink` +**基类**: `SQLModelBase`(关联表) + +| 字段 | 类型 | 说明 | +|------|------|------| +| `group_id` | `UUID` | 用户组(复合主键) | +| `policy_id` | `UUID` | 存储策略(复合主键) | + +--- + +### 6. Policy(存储策略) + +**表名**: `policy` +**基类**: `UUIDTableBase` + +| 字段 | 类型 | 说明 | +|------|------|------| +| `id` | `UUID` | 策略 UUID(主键) | +| `name` | `str` | 策略名称,唯一 | +| `type` | `PolicyType` | 策略类型:local/s3 | +| `server` | `str?` | 服务器地址 | +| `bucket_name` | `str?` | 存储桶名称 | +| `is_private` | `bool` | 是否为私有空间 | +| `base_url` | `str?` | 访问文件的基础 URL | +| `access_key` | `str?` | Access Key | +| `secret_key` | `str?` | Secret Key | +| `max_size` | `int` | 允许上传的最大文件尺寸(字节) | +| `auto_rename` | `bool` | 是否自动重命名 | +| `dir_name_rule` | `str?` | 目录命名规则 | +| `file_name_rule` | `str?` | 文件命名规则 | +| `is_origin_link_enable` | `bool` | 是否开启源链接访问 | +| `options` | `str?` | 其他选项(JSON 格式) | + +--- + +### 7. Object(统一对象) + +**表名**: `object` +**基类**: `UUIDTableBase` + +合并了文件和目录,通过 `type` 字段区分。 + +| 字段 | 类型 | 说明 | +|------|------|------| +| `id` | `UUID` | 对象 UUID(主键) | +| `name` | `str` | 对象名称(文件名或目录名) | +| `type` | `ObjectType` | 对象类型:file/folder | +| `password` | `str?` | 对象独立密码 | +| `source_name` | `str?` | 源文件名(仅文件) | +| `size` | `int` | 文件大小(字节),目录为 0 | +| `upload_session_id` | `str?` | 分块上传会话 ID | +| `file_metadata` | `str?` | 文件元数据(JSON 格式) | +| `parent_id` | `UUID?` | 父目录(外键,NULL 表示根目录) | +| `owner_id` | `UUID` | 所有者用户(外键) | +| `policy_id` | `UUID` | 存储策略(外键) | + +**约束**: +- 同一父目录下名称唯一 +- 名称不能包含斜杠 + +--- + +### 8. SourceLink(源链接) + +**表名**: `sourcelink` +**基类**: `TableBase` + +| 字段 | 类型 | 说明 | +|------|------|------| +| `id` | `int` | 主键 | +| `name` | `str` | 链接名称 | +| `downloads` | `int` | 通过此链接的下载次数 | +| `object_id` | `UUID` | 关联的对象(外键,必须是文件) | + +--- + +### 9. Share(分享) + +**表名**: `share` +**基类**: `TableBase` + +| 字段 | 类型 | 说明 | +|------|------|------| +| `id` | `int` | 主键 | +| `code` | `str` | 分享码,唯一 | +| `password` | `str?` | 分享密码(加密后) | +| `object_id` | `UUID` | 关联的对象(外键) | +| `views` | `int` | 浏览次数 | +| `downloads` | `int` | 下载次数 | +| `remain_downloads` | `int?` | 剩余下载次数(NULL 为不限制) | +| `expires` | `datetime?` | 过期时间(NULL 为永不过期) | +| `preview_enabled` | `bool` | 是否允许预览 | +| `source_name` | `str?` | 源名称(冗余字段) | +| `score` | `int` | 兑换所需积分 | +| `user_id` | `UUID` | 创建分享的用户(外键) | + +--- + +### 10. Report(举报) + +**表名**: `report` +**基类**: `TableBase` + +| 字段 | 类型 | 说明 | +|------|------|------| +| `id` | `int` | 主键 | +| `reason` | `int` | 举报原因代码 | +| `description` | `str?` | 补充描述 | +| `share_id` | `int` | 被举报的分享(外键) | + +--- + +### 11. Tag(标签) + +**表名**: `tag` +**基类**: `TableBase` + +| 字段 | 类型 | 说明 | +|------|------|------| +| `id` | `int` | 主键 | +| `name` | `str` | 标签名称 | +| `icon` | `str?` | 标签图标 | +| `color` | `str?` | 标签颜色 | +| `type` | `int` | 标签类型:0=手动,1=自动 | +| `expression` | `str?` | 自动标签的匹配表达式 | +| `user_id` | `UUID` | 所属用户(外键) | + +**约束**: 同一用户下标签名称唯一 + +--- + +### 12. Task(任务) + +**表名**: `task` +**基类**: `TableBase` + +| 字段 | 类型 | 说明 | +|------|------|------| +| `id` | `int` | 主键 | +| `status` | `int` | 任务状态:0=排队中,1=处理中,2=完成,3=错误 | +| `type` | `int` | 任务类型 | +| `progress` | `int` | 任务进度(0-100) | +| `error` | `str?` | 错误信息 | +| `props` | `str?` | 任务属性(JSON 格式) | +| `user_id` | `UUID` | 所属用户(外键) | + +--- + +### 13. Download(离线下载) + +**表名**: `download` +**基类**: `UUIDTableBase` + +| 字段 | 类型 | 说明 | +|------|------|------| +| `id` | `UUID` | 主键 | +| `status` | `int` | 下载状态:0=进行中,1=完成,2=错误 | +| `type` | `int` | 任务类型 | +| `source` | `str` | 来源 URL 或标识 | +| `total_size` | `int` | 总大小(字节) | +| `downloaded_size` | `int` | 已下载大小(字节) | +| `g_id` | `str?` | Aria2 GID | +| `speed` | `int` | 下载速度(bytes/s) | +| `parent` | `str?` | 父任务标识 | +| `attrs` | `str?` | 额外属性(JSON 格式) | +| `error` | `str?` | 错误信息 | +| `dst` | `str` | 目标存储路径 | +| `user_id` | `UUID` | 所属用户(外键) | +| `task_id` | `int?` | 关联的任务(外键) | +| `node_id` | `int` | 执行下载的节点(外键) | + +**约束**: 同一节点下 g_id 唯一 + +--- + +### 14. Node(节点) + +**表名**: `node` +**基类**: `TableBase` + +| 字段 | 类型 | 说明 | +|------|------|------| +| `id` | `int` | 主键 | +| `status` | `int` | 节点状态:0=正常,1=离线 | +| `name` | `str` | 节点名称,唯一 | +| `type` | `int` | 节点类型 | +| `server` | `str` | 节点地址(IP 或域名) | +| `slave_key` | `str?` | 从机通讯密钥 | +| `master_key` | `str?` | 主机通讯密钥 | +| `aria2_enabled` | `bool` | 是否启用 Aria2 | +| `aria2_options` | `str?` | Aria2 配置(JSON 格式) | +| `rank` | `int` | 节点排序权重 | + +--- + +### 15. Order(订单) + +**表名**: `order` +**基类**: `TableBase` + +| 字段 | 类型 | 说明 | +|------|------|------| +| `id` | `int` | 主键 | +| `order_no` | `str` | 订单号,唯一 | +| `type` | `int` | 订单类型 | +| `method` | `str?` | 支付方式 | +| `product_id` | `int?` | 商品 ID | +| `num` | `int` | 购买数量 | +| `name` | `str` | 商品名称 | +| `price` | `int` | 订单价格(分) | +| `status` | `int` | 订单状态:0=待支付,1=已完成,2=已取消 | +| `user_id` | `UUID` | 所属用户(外键) | + +--- + +### 16. Redeem(兑换码) + +**表名**: `redeem` +**基类**: `TableBase` + +| 字段 | 类型 | 说明 | +|------|------|------| +| `id` | `int` | 主键 | +| `type` | `int` | 兑换码类型 | +| `product_id` | `int?` | 关联的商品/权益 ID | +| `num` | `int` | 可兑换数量/时长等 | +| `code` | `str` | 兑换码,唯一 | +| `used` | `bool` | 是否已使用 | + +--- + +### 17. StoragePack(容量包) + +**表名**: `storagepack` +**基类**: `TableBase` + +| 字段 | 类型 | 说明 | +|------|------|------| +| `id` | `int` | 主键 | +| `name` | `str` | 容量包名称 | +| `active_time` | `datetime?` | 激活时间 | +| `expired_time` | `datetime?` | 过期时间 | +| `size` | `int` | 容量包大小(字节) | +| `user_id` | `UUID` | 所属用户(外键) | + +--- + +### 18. WebDAV(WebDAV 账户) + +**表名**: `webdav` +**基类**: `TableBase` + +| 字段 | 类型 | 说明 | +|------|------|------| +| `id` | `int` | 主键 | +| `name` | `str` | WebDAV 账户名 | +| `password` | `str` | WebDAV 密码 | +| `root` | `str` | 根目录路径(默认 /) | +| `readonly` | `bool` | 是否只读 | +| `use_proxy` | `bool` | 是否使用代理下载 | +| `user_id` | `UUID` | 所属用户(外键) | + +**约束**: 同一用户下账户名唯一 + +--- + +### 19. Setting(系统设置) + +**表名**: `setting` +**基类**: `TableBase` + +| 字段 | 类型 | 说明 | +|------|------|------| +| `id` | `int` | 主键 | +| `type` | `SettingsType` | 设置类型/分组 | +| `name` | `str` | 设置项名称 | +| `value` | `str?` | 设置值 | + +**约束**: type + name 唯一 + +**SettingsType 枚举值**: +`aria2`, `auth`, `authn`, `avatar`, `basic`, `captcha`, `cron`, `file_edit`, `login`, `mail`, `mail_template`, `mobile`, `path`, `preview`, `pwa`, `register`, `retry`, `share`, `slave`, `task`, `thumb`, `timeout`, `upload`, `version`, `view`, `wopi` + +--- + +## 模型关系图 + +### 一对一关系 + +``` +┌─────────────────────────────────────────────────────────┐ +│ 一对一关系 │ +├─────────────────────────────────────────────────────────┤ +│ │ +│ Group ◄────────────────────────► GroupOptions │ +│ group_id (unique FK) │ +│ │ +└─────────────────────────────────────────────────────────┘ +``` + +| 主表 | 从表 | 外键 | 说明 | +|------|------|------|------| +| Group | GroupOptions | `group_id` (unique) | 每个用户组有且仅有一个选项配置 | + +--- + +### 一对多关系 + +``` +┌─────────────────────────────────────────────────────────────────────────────┐ +│ 一对多关系 │ +├─────────────────────────────────────────────────────────────────────────────┤ +│ │ +│ ┌──────► Download │ +│ │ │ +│ ├──────► Object ◄──────┬──────► SourceLink │ +│ │ │ ▲ │ │ +│ │ │ │ └──────► Share ──────► Report│ +│ Group ──────► User ───┼─────────┘ │ │ +│ │ │ │ (自引用:parent-children) │ +│ │ ├──────► Order │ +│ │ │ │ +│ │ ├──────► StoragePack │ +│ │ │ │ +│ │ ├──────► Tag │ +│ │ │ │ +│ │ ├──────► Task ──────► Download │ +│ │ │ ▲ │ +│ │ ├──────► WebDAV │ │ +│ │ │ │ │ +│ │ └──────► UserAuthn │ │ +│ │ │ │ +│ └──────► Policy ──────► Object │ │ +│ │ │ +│ Node ───────────────┘ │ +│ │ +└─────────────────────────────────────────────────────────────────────────────┘ +``` + +| 一端 | 多端 | 外键 | 说明 | +|------|------|------|------| +| **Group** | User | `group_id` | 用户组包含多个用户 | +| **Group** | User | `previous_group_id` | 用户组过期后恢复关系 | +| **User** | Download | `user_id` | 用户的离线下载任务 | +| **User** | Object | `owner_id` | 用户拥有的文件/目录 | +| **User** | Order | `user_id` | 用户的订单 | +| **User** | Share | `user_id` | 用户创建的分享 | +| **User** | StoragePack | `user_id` | 用户的容量包 | +| **User** | Tag | `user_id` | 用户的标签 | +| **User** | Task | `user_id` | 用户的任务 | +| **User** | WebDAV | `user_id` | 用户的 WebDAV 账户 | +| **User** | UserAuthn | `user_id` | 用户的 WebAuthn 凭证 | +| **Policy** | Object | `policy_id` | 存储策略下的对象 | +| **Object** | Object | `parent_id` | 目录的子文件/子目录(自引用) | +| **Object** | SourceLink | `object_id` | 文件的源链接 | +| **Object** | Share | `object_id` | 对象的分享 | +| **Share** | Report | `share_id` | 分享的举报 | +| **Task** | Download | `task_id` | 任务关联的下载 | +| **Node** | Download | `node_id` | 节点执行的下载任务 | + +--- + +### 多对多关系 + +``` +┌─────────────────────────────────────────────────────────┐ +│ 多对多关系 │ +├─────────────────────────────────────────────────────────┤ +│ │ +│ Group ◄────── GroupPolicyLink ──────► Policy │ +│ │ +│ - 一个用户组可以使用多个存储策略 │ +│ - 一个存储策略可以被多个用户组使用 │ +│ │ +└─────────────────────────────────────────────────────────┘ +``` + +| 表1 | 表2 | 关联表 | 说明 | +|-----|-----|--------|------| +| Group | Policy | GroupPolicyLink | 用户组可使用的存储策略 | + +--- + +## 完整关系 ER 图 + +``` + ┌──────────────┐ + │ Setting │ + │ (独立表) │ + └──────────────┘ + + ┌──────────────┐ + │ Redeem │ + │ (独立表) │ + └──────────────┘ + +┌──────────────┐ 1:1 ┌──────────────┐ +│ Group │◄────────────►│ GroupOptions │ +│ │ └──────────────┘ +│ │ +│ │──────┐ M:N ┌──────────────────┐ +│ │ └──────►│ GroupPolicyLink │◄───┐ +└──────┬───────┘ └──────────────────┘ │ + │ │ + │ 1:N │ + ▼ │ +┌──────────────┐ ┌──────────────┐ │ +│ User │ │ Policy │◄───────┘ +│ │ │ │ +│ │ └──────┬───────┘ +│ │ │ 1:N +│ │──────────────┐ │ +└──────┬───────┘ │ │ + │ │ ▼ + │ 1:N │ ┌──────────────┐ ┌──────────────┐ + │ │ │ Object │◄────►│ Object │ + │ │ │ │ │ (children) │ + │ │ │ │ └──────────────┘ + ├──────────────────────┼─┤ │ + │ │ └──────┬───────┘ + │ │ │ + │ │ │ 1:N + │ │ ├─────────────►┌──────────────┐ + │ │ │ │ SourceLink │ + │ │ │ └──────────────┘ + │ │ │ + │ │ │ 1:N + │ │ └─────────────►┌──────────────┐ + │ │ │ Share │ + │ │ │ │─────► Report + │ │ └──────────────┘ + │ │ + ├──► Download ◄────────┼───────────────────────── Task + │ ▲ │ + │ │ │ + │ │ │ + │ └─────────────┼─────────────────────── Node + │ │ + ├──► Order │ + │ │ + ├──► StoragePack │ + │ │ + ├──► Tag │ + │ │ + ├──► WebDAV │ + │ │ + └──► UserAuthn │ + │ + │ +``` + +--- + +## 枚举类型 + +### ObjectType +```python +class ObjectType(StrEnum): + FILE = "file" # 文件 + FOLDER = "folder" # 目录 +``` + +### PolicyType +```python +class PolicyType(StrEnum): + LOCAL = "local" # 本地存储 + S3 = "s3" # S3 兼容存储 +``` + +### ThemeType +```python +class ThemeType(StrEnum): + LIGHT = "light" # 浅色主题 + DARK = "dark" # 深色主题 + SYSTEM = "system" # 跟随系统 +``` + +### AvatarType +```python +class AvatarType(StrEnum): + DEFAULT = "default" # 默认头像 + GRAVATAR = "gravatar" # Gravatar + FILE = "file" # 自定义文件 +``` + +--- + +## DTO 模型 + +### 用户相关 + +| DTO | 说明 | +|-----|------| +| `LoginRequest` | 登录请求 | +| `RegisterRequest` | 注册请求 | +| `TokenResponse` | 访问令牌响应 | +| `UserResponse` | 用户信息响应 | +| `UserPublic` | 用户公开信息 | +| `UserSettingResponse` | 用户设置响应 | +| `WebAuthnInfo` | WebAuthn 信息 | +| `AuthnResponse` | WebAuthn 响应 | + +### 用户组相关 + +| DTO | 说明 | +|-----|------| +| `GroupBase` | 用户组基础字段 | +| `GroupOptionsBase` | 用户组选项基础字段 | +| `GroupResponse` | 用户组响应 | + +### 对象相关 + +| DTO | 说明 | +|-----|------| +| `ObjectBase` | 对象基础字段 | +| `ObjectResponse` | 对象响应 | +| `DirectoryCreateRequest` | 创建目录请求 | +| `DirectoryResponse` | 目录响应 | +| `ObjectMoveRequest` | 移动对象请求 | +| `ObjectDeleteRequest` | 删除对象请求 | +| `PolicyResponse` | 存储策略响应 | + +### 其他 + +| DTO | 说明 | +|-----|------| +| `SiteConfigResponse` | 站点配置响应 | +| `ThemeResponse` | 主题颜色响应 | + +--- + +## 使用示例 + +### 查询用户及其关联数据 + +```python +from sqlalchemy.orm import selectinload + +# 获取用户及其用户组 +user = await User.get( + session, + User.id == user_id, + load=User.group +) + +# 获取用户的所有文件 +objects = await Object.get( + session, + (Object.owner_id == user_id) & (Object.type == ObjectType.FILE), + fetch_mode="all" +) +``` + +### 创建文件对象 + +```python +file = Object( + name="example.txt", + type=ObjectType.FILE, + size=1024, + owner_id=user.id, + parent_id=folder.id, + policy_id=policy.id +) +file = await file.save(session) +``` + +### 多对多关系操作 + +```python +# 为用户组添加存储策略 +group.policies.append(policy) +await group.save(session) +``` diff --git a/models/group.py b/models/group.py index 4563c51..28f9d4b 100644 --- a/models/group.py +++ b/models/group.py @@ -96,9 +96,6 @@ class GroupOptions(GroupOptionsBase, TableBase, table=True): redirected_source: bool = False """是否使用重定向源""" - available_nodes: str = "[]" - """可用节点ID列表(JSON数组)""" - # 反向关系 group: "Group" = Relationship(back_populates="options") diff --git a/utils/password/pwd.py b/utils/password/pwd.py index 5043c81..99cdda3 100644 --- a/utils/password/pwd.py +++ b/utils/password/pwd.py @@ -4,7 +4,7 @@ from argon2 import PasswordHasher from argon2.exceptions import VerifyMismatchError from enum import StrEnum import pyotp -from itsdangerous import URLSafeTimedSerializer, BadSignature, SignatureExpired +from itsdangerous import URLSafeTimedSerializer from pydantic import BaseModel, Field from utils.JWT.JWT import SECRET_KEY