Files
disknext/models/README.md
于小丘 6c3a601259 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.
2025-12-19 20:18:36 +08:00

734 lines
26 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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. UserAuthnWebAuthn 凭证)
**表名**: `userauthn`
**基类**: `TableBase`
| 字段 | 类型 | 说明 |
|------|------|------|
| `id` | `int` | 主键 |
| `credential_id` | `str` | 凭证 IDBase64 编码) |
| `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/s0 为不限制 |
---
### 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. WebDAVWebDAV 账户)
**表名**: `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)
```