数据库创建
This commit is contained in:
30
models/__init__.py
Normal file
30
models/__init__.py
Normal file
@@ -0,0 +1,30 @@
|
||||
# my_project/models/__init__.py
|
||||
|
||||
from . import response
|
||||
|
||||
# 将所有模型导入到这个包的命名空间中
|
||||
from .base import BaseModel
|
||||
from .download import Download
|
||||
from .file import File
|
||||
from .folder import Folder
|
||||
from .group import Group
|
||||
from .node import Node
|
||||
from .order import Order
|
||||
from .policy import Policy
|
||||
from .redeem import Redeem
|
||||
from .report import Report
|
||||
from .setting import Setting
|
||||
from .share import Share
|
||||
from .source_link import SourceLink
|
||||
from .storage_pack import StoragePack
|
||||
from .tag import Tag
|
||||
from .task import Task
|
||||
from .user import User
|
||||
from .webdav import WebDAV
|
||||
|
||||
# 可以定义一个 __all__ 列表来明确指定可以被 from .models import * 导入的内容
|
||||
__all__ = [
|
||||
"BaseModel", "Download", "File", "Folder", "Group", "Node", "Order",
|
||||
"Policy", "Redeem", "Report", "Setting", "Share", "SourceLink",
|
||||
"StoragePack", "Tag", "Task", "User", "WebDAV"
|
||||
]
|
||||
9
models/base.py
Normal file
9
models/base.py
Normal file
@@ -0,0 +1,9 @@
|
||||
# my_project/models/base.py
|
||||
|
||||
from typing import Optional
|
||||
from sqlmodel import SQLModel, Field
|
||||
|
||||
class BaseModel(SQLModel):
|
||||
__abstract__ = True
|
||||
|
||||
id: Optional[int] = Field(default=None, primary_key=True, description="主键ID")
|
||||
31
models/database.py
Normal file
31
models/database.py
Normal file
@@ -0,0 +1,31 @@
|
||||
# my_project/database.py
|
||||
|
||||
from sqlmodel import SQLModel
|
||||
from sqlalchemy.ext.asyncio import create_async_engine
|
||||
from sqlmodel.ext.asyncio.session import AsyncSession
|
||||
from sqlalchemy.orm import sessionmaker
|
||||
|
||||
ASYNC_DATABASE_URL = "sqlite+aiosqlite:///database.db"
|
||||
|
||||
engine = create_async_engine(
|
||||
ASYNC_DATABASE_URL,
|
||||
echo=True,
|
||||
connect_args={"check_same_thread": False}
|
||||
if ASYNC_DATABASE_URL.startswith("sqlite")
|
||||
else None,
|
||||
future=True,
|
||||
# pool_size=POOL_SIZE,
|
||||
# max_overflow=64,
|
||||
)
|
||||
|
||||
_async_session_factory = sessionmaker(engine, class_=AsyncSession)
|
||||
|
||||
async def get_session():
|
||||
async with _async_session_factory() as session:
|
||||
yield session
|
||||
|
||||
async def init_db():
|
||||
"""初始化数据库"""
|
||||
# 创建所有表
|
||||
async with engine.begin() as conn:
|
||||
await conn.run_sync(SQLModel.metadata.create_all)
|
||||
56
models/download.py
Normal file
56
models/download.py
Normal file
@@ -0,0 +1,56 @@
|
||||
# my_project/models/download.py
|
||||
|
||||
from typing import Optional, TYPE_CHECKING
|
||||
from sqlmodel import Field, Relationship, Column, func, DateTime
|
||||
from .base import BaseModel
|
||||
from datetime import datetime
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .user import User
|
||||
from .task import Task
|
||||
from .node import Node
|
||||
|
||||
class Download(BaseModel, table=True):
|
||||
__tablename__ = 'downloads'
|
||||
|
||||
status: int = Field(default=0, sa_column_kwargs={"server_default": "0"}, description="下载状态: 0=进行中, 1=完成, 2=错误")
|
||||
type: int = Field(default=0, sa_column_kwargs={"server_default": "0"}, description="任务类型")
|
||||
source: str = Field(description="来源URL或标识")
|
||||
total_size: int = Field(default=0, sa_column_kwargs={"server_default": "0"}, description="总大小(字节)")
|
||||
downloaded_size: int = Field(default=0, sa_column_kwargs={"server_default": "0"}, description="已下载大小(字节)")
|
||||
g_id: Optional[str] = Field(default=None, index=True, description="Aria2 GID")
|
||||
speed: int = Field(default=0, sa_column_kwargs={"server_default": "0"}, description="下载速度 (bytes/s)")
|
||||
parent: Optional[str] = Field(default=None, description="父任务标识")
|
||||
attrs: Optional[str] = Field(default=None, description="额外属性 (JSON格式)")
|
||||
error: Optional[str] = Field(default=None, description="错误信息")
|
||||
dst: str = Field(description="目标存储路径")
|
||||
created_at: Optional[datetime] = Field(
|
||||
default=None,
|
||||
sa_column=Column(
|
||||
DateTime,
|
||||
nullable=False,
|
||||
server_default=func.now(),
|
||||
comment="创建时间",
|
||||
),
|
||||
)
|
||||
|
||||
updated_at: Optional[datetime] = Field(
|
||||
default=None,
|
||||
sa_column=Column(
|
||||
DateTime,
|
||||
nullable=False,
|
||||
server_default=func.now(),
|
||||
onupdate=func.now(),
|
||||
comment="更新时间",
|
||||
),
|
||||
)
|
||||
|
||||
# 外键
|
||||
user_id: int = Field(foreign_key="users.id", index=True, description="所属用户ID")
|
||||
task_id: Optional[int] = Field(default=None, foreign_key="tasks.id", index=True, description="关联的任务ID")
|
||||
node_id: int = Field(foreign_key="nodes.id", index=True, description="执行下载的节点ID")
|
||||
|
||||
# 关系
|
||||
user: "User" = Relationship(back_populates="downloads")
|
||||
task: Optional["Task"] = Relationship(back_populates="downloads")
|
||||
node: "Node" = Relationship(back_populates="downloads")
|
||||
53
models/file.py
Normal file
53
models/file.py
Normal file
@@ -0,0 +1,53 @@
|
||||
# my_project/models/file.py
|
||||
|
||||
from typing import Optional, TYPE_CHECKING
|
||||
from sqlmodel import Field, Relationship, Column, func, DateTime
|
||||
from .base import BaseModel
|
||||
from datetime import datetime
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .user import User
|
||||
from .folder import Folder
|
||||
from .policy import Policy
|
||||
from .source_link import SourceLink
|
||||
|
||||
class File(BaseModel, table=True):
|
||||
__tablename__ = 'files'
|
||||
|
||||
name: str = Field(max_length=255, description="文件名")
|
||||
source_name: Optional[str] = Field(default=None, description="源文件名")
|
||||
size: int = Field(default=0, sa_column_kwargs={"server_default": "0"}, description="文件大小(字节)")
|
||||
pic_info: Optional[str] = Field(default=None, max_length=255, description="图片信息(如尺寸)")
|
||||
upload_session_id: Optional[str] = Field(default=None, max_length=255, unique=True, index=True, description="分块上传会话ID")
|
||||
file_metadata: Optional[str] = Field(default=None, description="文件元数据 (JSON格式)")
|
||||
created_at: Optional[datetime] = Field(
|
||||
default=None,
|
||||
sa_column=Column(
|
||||
DateTime,
|
||||
nullable=False,
|
||||
server_default=func.now(),
|
||||
comment="创建时间",
|
||||
),
|
||||
)
|
||||
|
||||
updated_at: Optional[datetime] = Field(
|
||||
default=None,
|
||||
sa_column=Column(
|
||||
DateTime,
|
||||
nullable=False,
|
||||
server_default=func.now(),
|
||||
onupdate=func.now(),
|
||||
comment="更新时间",
|
||||
),
|
||||
)
|
||||
|
||||
# 外键
|
||||
user_id: int = Field(foreign_key="users.id", index=True, description="所属用户ID")
|
||||
folder_id: int = Field(foreign_key="folders.id", index=True, description="所在目录ID")
|
||||
policy_id: int = Field(foreign_key="policies.id", index=True, description="所属存储策略ID")
|
||||
|
||||
# 关系
|
||||
user: list["User"] = Relationship(back_populates="files")
|
||||
folder: list["Folder"] = Relationship(back_populates="files")
|
||||
policy: list["Policy"] = Relationship(back_populates="files")
|
||||
source_links: list["SourceLink"] = Relationship(back_populates="file")
|
||||
52
models/folder.py
Normal file
52
models/folder.py
Normal file
@@ -0,0 +1,52 @@
|
||||
# my_project/models/folder.py
|
||||
|
||||
from typing import Optional, List, TYPE_CHECKING
|
||||
from sqlmodel import Field, Relationship, UniqueConstraint, Column, func, DateTime
|
||||
from .base import BaseModel
|
||||
from datetime import datetime
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .user import User
|
||||
from .policy import Policy
|
||||
from .file import File
|
||||
|
||||
class Folder(BaseModel, table=True):
|
||||
__tablename__ = 'folders'
|
||||
__table_args__ = (UniqueConstraint("name", "parent_id", name="uq_folder_name_parent"),)
|
||||
|
||||
name: str = Field(max_length=255, description="目录名")
|
||||
created_at: Optional[datetime] = Field(
|
||||
default=None,
|
||||
sa_column=Column(
|
||||
DateTime,
|
||||
nullable=False,
|
||||
server_default=func.now(),
|
||||
comment="创建时间",
|
||||
),
|
||||
)
|
||||
|
||||
updated_at: Optional[datetime] = Field(
|
||||
default=None,
|
||||
sa_column=Column(
|
||||
DateTime,
|
||||
nullable=False,
|
||||
server_default=func.now(),
|
||||
onupdate=func.now(),
|
||||
comment="更新时间",
|
||||
),
|
||||
)
|
||||
|
||||
# 外键
|
||||
parent_id: Optional[int] = Field(default=None, foreign_key="folders.id", index=True, description="父目录ID")
|
||||
owner_id: int = Field(foreign_key="users.id", index=True, description="所有者用户ID")
|
||||
policy_id: int = Field(foreign_key="policies.id", index=True, description="所属存储策略ID")
|
||||
|
||||
# 关系
|
||||
owner: "User" = Relationship(back_populates="folders")
|
||||
policy: "Policy" = Relationship(back_populates="folders")
|
||||
|
||||
# 自我引用关系
|
||||
parent: Optional["Folder"] = Relationship(back_populates="children", sa_relationship_kwargs={"remote_side": "Folder.id"})
|
||||
children: List["Folder"] = Relationship(back_populates="parent")
|
||||
|
||||
files: List["File"] = Relationship(back_populates="folder")
|
||||
44
models/group.py
Normal file
44
models/group.py
Normal file
@@ -0,0 +1,44 @@
|
||||
# my_project/models/group.py
|
||||
|
||||
from typing import Optional, List, TYPE_CHECKING
|
||||
from sqlmodel import Field, Relationship, text, Column, func, DateTime
|
||||
from .base import BaseModel
|
||||
from datetime import datetime
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .user import User
|
||||
|
||||
class Group(BaseModel, table=True):
|
||||
__tablename__ = 'groups'
|
||||
|
||||
name: str = Field(max_length=255, unique=True, description="用户组名")
|
||||
policies: Optional[str] = Field(default=None, max_length=255, description="允许的策略ID列表,逗号分隔")
|
||||
max_storage: int = Field(default=0, sa_column_kwargs={"server_default": "0"}, description="最大存储空间(字节)")
|
||||
share_enabled: bool = Field(default=False, sa_column_kwargs={"server_default": text("false")}, description="是否允许创建分享")
|
||||
web_dav_enabled: bool = Field(default=False, sa_column_kwargs={"server_default": text("false")}, description="是否允许使用WebDAV")
|
||||
speed_limit: int = Field(default=0, sa_column_kwargs={"server_default": "0"}, description="速度限制 (KB/s), 0为不限制")
|
||||
options: Optional[str] = Field(default=None, description="其他选项 (JSON格式)")
|
||||
created_at: Optional[datetime] = Field(
|
||||
default=None,
|
||||
sa_column=Column(
|
||||
DateTime,
|
||||
nullable=False,
|
||||
server_default=func.now(),
|
||||
comment="创建时间",
|
||||
),
|
||||
)
|
||||
|
||||
updated_at: Optional[datetime] = Field(
|
||||
default=None,
|
||||
sa_column=Column(
|
||||
DateTime,
|
||||
nullable=False,
|
||||
server_default=func.now(),
|
||||
onupdate=func.now(),
|
||||
comment="更新时间",
|
||||
),
|
||||
)
|
||||
|
||||
# 关系:一个组可以有多个用户
|
||||
users: List["User"] = Relationship(back_populates="group")
|
||||
previous_users: List["User"] = Relationship(back_populates="previous_group")
|
||||
251
models/model.py
251
models/model.py
@@ -1,251 +0,0 @@
|
||||
from sqlalchemy import (
|
||||
Column, Integer, String, Text, BigInteger, Boolean, DateTime,
|
||||
ForeignKey, func, text, UniqueConstraint
|
||||
)
|
||||
from sqlalchemy.orm import declarative_base
|
||||
|
||||
Base = declarative_base()
|
||||
|
||||
class BaseModel(Base):
|
||||
__abstract__ = True
|
||||
|
||||
id = Column(Integer, primary_key=True, comment="主键ID")
|
||||
|
||||
created_at = Column(
|
||||
DateTime,
|
||||
server_default=func.now(),
|
||||
comment="创建时间"
|
||||
)
|
||||
|
||||
updated_at = Column(
|
||||
DateTime,
|
||||
server_default=func.now(),
|
||||
onupdate=func.now(),
|
||||
server_onupdate=func.now(),
|
||||
comment="更新时间"
|
||||
)
|
||||
|
||||
deleted_at = Column(DateTime, nullable=True, comment="软删除时间")
|
||||
|
||||
class Download(BaseModel):
|
||||
__tablename__ = 'downloads'
|
||||
|
||||
status = Column(Integer, nullable=False, server_default='0', comment="下载状态: 0=进行中, 1=完成, 2=错误")
|
||||
type = Column(Integer, nullable=False, server_default='0', comment="任务类型")
|
||||
source = Column(Text, nullable=False, comment="来源URL或标识")
|
||||
total_size = Column(BigInteger, nullable=False, server_default='0', comment="总大小(字节)")
|
||||
downloaded_size = Column(BigInteger, nullable=False, server_default='0', comment="已下载大小(字节)")
|
||||
g_id = Column(Text, index=True, comment="Aria2 GID") # GID经常用于查询,建议索引
|
||||
speed = Column(Integer, nullable=False, server_default='0', comment="下载速度 (bytes/s)")
|
||||
parent = Column(Text, comment="父任务标识")
|
||||
attrs = Column(Text, comment="额外属性 (JSON格式)")
|
||||
error = Column(Text, comment="错误信息")
|
||||
dst = Column(Text, nullable=False, comment="目标存储路径")
|
||||
|
||||
user_id = Column(Integer, ForeignKey('users.id'), nullable=False, index=True, comment="所属用户ID")
|
||||
task_id = Column(Integer, ForeignKey('tasks.id'), nullable=True, index=True, comment="关联的任务ID")
|
||||
node_id = Column(Integer, ForeignKey('nodes.id'), nullable=False, index=True, comment="执行下载的节点ID")
|
||||
|
||||
class File(BaseModel):
|
||||
__tablename__ = 'files'
|
||||
|
||||
name = Column(String(255), nullable=False, comment="文件名")
|
||||
source_name = Column(Text, comment="源文件名")
|
||||
size = Column(BigInteger, nullable=False, server_default='0', comment="文件大小(字节)")
|
||||
pic_info = Column(String(255), comment="图片信息(如尺寸)")
|
||||
upload_session_id = Column(String(255), unique=True, index=True, comment="分块上传会话ID")
|
||||
metadata = Column(Text, comment="文件元数据 (JSON格式)")
|
||||
|
||||
user_id = Column(Integer, ForeignKey('users.id'), nullable=False, index=True, comment="所属用户ID")
|
||||
folder_id = Column(Integer, ForeignKey('folders.id'), nullable=False, index=True, comment="所在目录ID")
|
||||
policy_id = Column(Integer, ForeignKey('policies.id'), nullable=False, index=True, comment="所属存储策略ID")
|
||||
|
||||
class Folder(BaseModel):
|
||||
__tablename__ = 'folders'
|
||||
|
||||
name = Column(String(255), nullable=False, comment="目录名")
|
||||
|
||||
parent_id = Column(Integer, ForeignKey('folders.id'), nullable=True, index=True, comment="父目录ID")
|
||||
owner_id = Column(Integer, ForeignKey('users.id'), nullable=False, index=True, comment="所有者用户ID")
|
||||
policy_id = Column(Integer, ForeignKey('policies.id'), nullable=False, index=True, comment="所属存储策略ID")
|
||||
|
||||
__table_args__ = (
|
||||
UniqueConstraint('name', 'parent_id', name='uq_folder_name_parent'),
|
||||
)
|
||||
|
||||
class Group(BaseModel):
|
||||
__tablename__ = 'groups'
|
||||
|
||||
name = Column(String(255), nullable=False, unique=True, comment="用户组名")
|
||||
policies = Column(String(255), comment="允许的策略ID列表,逗号分隔")
|
||||
max_storage = Column(BigInteger, nullable=False, server_default='0', comment="最大存储空间(字节)")
|
||||
|
||||
share_enabled = Column(Boolean, nullable=False, server_default=text('false'), comment="是否允许创建分享")
|
||||
web_dav_enabled = Column(Boolean, nullable=False, server_default=text('false'), comment="是否允许使用WebDAV")
|
||||
|
||||
speed_limit = Column(Integer, nullable=False, server_default='0', comment="速度限制 (KB/s), 0为不限制")
|
||||
options = Column(Text, comment="其他选项 (JSON格式)")
|
||||
|
||||
class Node(BaseModel):
|
||||
__tablename__ = 'nodes'
|
||||
|
||||
status = Column(Integer, nullable=False, server_default='0', comment="节点状态: 0=正常, 1=离线")
|
||||
name = Column(String(255), nullable=False, unique=True, comment="节点名称")
|
||||
type = Column(Integer, nullable=False, server_default='0', comment="节点类型")
|
||||
server = Column(String(255), nullable=False, comment="节点地址(IP或域名)")
|
||||
slave_key = Column(Text, comment="从机通讯密钥")
|
||||
master_key = Column(Text, comment="主机通讯密钥")
|
||||
aria2_enabled = Column(Boolean, nullable=False, server_default=text('false'), comment="是否启用Aria2")
|
||||
aria2_options = Column(Text, comment="Aria2配置 (JSON格式)")
|
||||
rank = Column(Integer, nullable=False, server_default='0', comment="节点排序权重")
|
||||
|
||||
class Order(BaseModel):
|
||||
__tablename__ = 'orders'
|
||||
|
||||
order_no = Column(String(255), nullable=False, unique=True, index=True, comment="订单号,唯一")
|
||||
type = Column(Integer, nullable=False, comment="订单类型")
|
||||
method = Column(String(255), comment="支付方式")
|
||||
product_id = Column(BigInteger, comment="商品ID")
|
||||
num = Column(Integer, nullable=False, server_default='1', comment="购买数量")
|
||||
name = Column(String(255), nullable=False, comment="商品名称")
|
||||
price = Column(Integer, nullable=False, server_default='0', comment="订单价格(分)")
|
||||
status = Column(Integer, nullable=False, server_default='0', comment="订单状态: 0=待支付, 1=已完成, 2=已取消")
|
||||
|
||||
user_id = Column(Integer, ForeignKey('users.id'), nullable=False, index=True, comment="所属用户ID")
|
||||
|
||||
class Policy(BaseModel):
|
||||
__tablename__ = 'policies'
|
||||
|
||||
name = Column(String(255), nullable=False, unique=True, comment="策略名称")
|
||||
type = Column(String(255), nullable=False, comment="存储类型 (e.g. 'local', 's3')")
|
||||
server = Column(String(255), comment="服务器地址(本地策略为路径)")
|
||||
bucket_name = Column(String(255), comment="存储桶名称")
|
||||
is_private = Column(Boolean, nullable=False, server_default=text('true'), comment="是否为私有空间")
|
||||
base_url = Column(String(255), comment="访问文件的基础URL")
|
||||
access_key = Column(Text, comment="Access Key")
|
||||
secret_key = Column(Text, comment="Secret Key")
|
||||
max_size = Column(BigInteger, nullable=False, server_default='0', comment="允许上传的最大文件尺寸(字节)")
|
||||
auto_rename = Column(Boolean, nullable=False, server_default=text('false'), comment="是否自动重命名")
|
||||
dir_name_rule = Column(String(255), comment="目录命名规则")
|
||||
file_name_rule = Column(String(255), comment="文件命名规则")
|
||||
is_origin_link_enable = Column(Boolean, nullable=False, server_default=text('false'), comment="是否开启源链接访问")
|
||||
options = Column(Text, comment="其他选项 (JSON格式)")
|
||||
|
||||
class Setting(BaseModel):
|
||||
__tablename__ = 'settings'
|
||||
|
||||
# 优化点: type和name的组合应该是唯一的
|
||||
type = Column(String(255), nullable=False, comment="设置类型/分组")
|
||||
name = Column(String(255), nullable=False, comment="设置项名称")
|
||||
value = Column(Text, comment="设置值")
|
||||
|
||||
__table_args__ = (
|
||||
UniqueConstraint('type', 'name', name='uq_setting_type_name'),
|
||||
)
|
||||
|
||||
class Share(BaseModel):
|
||||
__tablename__ = 'shares'
|
||||
|
||||
password = Column(String(255), comment="分享密码(加密后)")
|
||||
is_dir = Column(Boolean, nullable=False, server_default=text('false'), comment="是否为目录分享")
|
||||
source_id = Column(Integer, nullable=False, comment="源文件或目录的ID")
|
||||
views = Column(Integer, nullable=False, server_default='0', comment="浏览次数")
|
||||
downloads = Column(Integer, nullable=False, server_default='0', comment="下载次数")
|
||||
remain_downloads = Column(Integer, comment="剩余下载次数 (NULL为不限制)")
|
||||
expires = Column(DateTime, comment="过期时间 (NULL为永不过期)")
|
||||
preview_enabled = Column(Boolean, nullable=False, server_default=text('true'), comment="是否允许预览")
|
||||
source_name = Column(String(255), index=True, comment="源名称(冗余字段,便于展示)")
|
||||
score = Column(Integer, nullable=False, server_default='0', comment="分享评分/权重")
|
||||
|
||||
user_id = Column(Integer, ForeignKey('users.id'), nullable=False, index=True, comment="创建分享的用户ID")
|
||||
|
||||
class Task(BaseModel):
|
||||
__tablename__ = 'tasks'
|
||||
|
||||
status = Column(Integer, nullable=False, server_default='0', comment="任务状态: 0=排队中, 1=处理中, 2=完成, 3=错误")
|
||||
type = Column(Integer, nullable=False, comment="任务类型")
|
||||
progress = Column(Integer, nullable=False, server_default='0', comment="任务进度 (0-100)")
|
||||
error = Column(Text, comment="错误信息")
|
||||
props = Column(Text, comment="任务属性 (JSON格式)")
|
||||
|
||||
user_id = Column(Integer, ForeignKey('users.id'), nullable=False, index=True, comment="所属用户ID")
|
||||
|
||||
class User(BaseModel):
|
||||
__tablename__ = 'users'
|
||||
|
||||
email = Column(String(100), nullable=False, unique=True, index=True, comment="用户邮箱,唯一")
|
||||
nick = Column(String(50), comment="用户昵称")
|
||||
password = Column(String(255), nullable=False, comment="用户密码(加密后)")
|
||||
status = Column(Integer, nullable=False, server_default='0', comment="用户状态: 0=正常, 1=未激活, 2=封禁")
|
||||
storage = Column(BigInteger, nullable=False, server_default='0', comment="已用存储空间(字节)")
|
||||
two_factor = Column(String(255), comment="两步验证密钥")
|
||||
avatar = Column(String(255), comment="头像地址")
|
||||
options = Column(Text, comment="用户个人设置 (JSON格式)")
|
||||
authn = Column(Text, comment="WebAuthn 凭证")
|
||||
open_id = Column(String(255), unique=True, index=True, nullable=True, comment="第三方登录OpenID")
|
||||
score = Column(Integer, nullable=False, server_default='0', comment="用户积分")
|
||||
group_expires = Column(DateTime, comment="当前用户组过期时间")
|
||||
phone = Column(String(255), unique=True, nullable=True, index=True, comment="手机号")
|
||||
|
||||
group_id = Column(Integer, ForeignKey('groups.id'), nullable=False, index=True, comment="所属用户组ID")
|
||||
previous_group_id = Column(Integer, ForeignKey('groups.id'), nullable=True, comment="之前的用户组ID(用于过期后恢复)")
|
||||
|
||||
class Redeem(BaseModel):
|
||||
__tablename__ = 'redeems'
|
||||
|
||||
type = Column(Integer, nullable=False, comment="兑换码类型")
|
||||
product_id = Column(BigInteger, comment="关联的商品/权益ID")
|
||||
num = Column(Integer, nullable=False, server_default='1', comment="可兑换数量/时长等")
|
||||
code = Column(Text, nullable=False, unique=True, index=True, comment="兑换码,唯一")
|
||||
used = Column(Boolean, nullable=False, server_default=text('false'), comment="是否已使用")
|
||||
|
||||
class Report(BaseModel):
|
||||
__tablename__ = 'reports'
|
||||
|
||||
share_id = Column(Integer, ForeignKey('shares.id'), index=True, nullable=False, comment="被举报的分享ID")
|
||||
reason = Column(Integer, nullable=False, comment="举报原因代码")
|
||||
description = Column(String(255), comment="补充描述")
|
||||
|
||||
class SourceLink(BaseModel):
|
||||
__tablename__ = 'source_links'
|
||||
|
||||
file_id = Column(Integer, ForeignKey('files.id'), nullable=False, index=True, comment="关联的文件ID")
|
||||
name = Column(String(255), nullable=False, comment="链接名称")
|
||||
downloads = Column(Integer, nullable=False, server_default='0', comment="通过此链接的下载次数")
|
||||
|
||||
class StoragePack(BaseModel):
|
||||
__tablename__ = 'storage_packs'
|
||||
|
||||
name = Column(String(255), nullable=False, comment="容量包名称")
|
||||
active_time = Column(DateTime, comment="激活时间")
|
||||
expired_time = Column(DateTime, index=True, comment="过期时间")
|
||||
size = Column(BigInteger, nullable=False, comment="容量包大小(字节)")
|
||||
user_id = Column(Integer, ForeignKey('users.id'), nullable=False, index=True, comment="所属用户ID")
|
||||
|
||||
class Tag(BaseModel):
|
||||
__tablename__ = 'tags'
|
||||
|
||||
name = Column(String(255), nullable=False, comment="标签名称")
|
||||
icon = Column(String(255), comment="标签图标")
|
||||
color = Column(String(255), comment="标签颜色")
|
||||
type = Column(Integer, nullable=False, server_default='0', comment="标签类型: 0=手动, 1=自动")
|
||||
expression = Column(Text, comment="自动标签的匹配表达式")
|
||||
user_id = Column(Integer, ForeignKey('users.id'), nullable=False, index=True, comment="所属用户ID")
|
||||
|
||||
__table_args__ = (
|
||||
UniqueConstraint('name', 'user_id', name='uq_tag_name_user'),
|
||||
)
|
||||
|
||||
class WebDAV(BaseModel):
|
||||
__tablename__ = 'webdavs'
|
||||
|
||||
name = Column(String(255), nullable=False, comment="WebDAV账户名")
|
||||
password = Column(String(255), nullable=False, comment="WebDAV密码(加密后)")
|
||||
root = Column(Text, nullable=False, server_default="'/'", comment="根目录路径")
|
||||
readonly = Column(Boolean, nullable=False, server_default=text('false'), comment="是否只读")
|
||||
use_proxy = Column(Boolean, nullable=False, server_default=text('false'), comment="是否使用代理下载")
|
||||
user_id = Column(Integer, ForeignKey('users.id'), nullable=False, index=True, comment="所属用户ID")
|
||||
|
||||
__table_args__ = (
|
||||
UniqueConstraint('name', 'user_id', name='uq_webdav_name_user'),
|
||||
)
|
||||
45
models/node.py
Normal file
45
models/node.py
Normal file
@@ -0,0 +1,45 @@
|
||||
# my_project/models/node.py
|
||||
|
||||
from typing import Optional, TYPE_CHECKING
|
||||
from sqlmodel import Field, Relationship, text, Column, func, DateTime
|
||||
from .base import BaseModel
|
||||
from datetime import datetime
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .download import Download
|
||||
|
||||
class Node(BaseModel, table=True):
|
||||
__tablename__ = 'nodes'
|
||||
|
||||
status: int = Field(default=0, sa_column_kwargs={"server_default": "0"}, description="节点状态: 0=正常, 1=离线")
|
||||
name: str = Field(max_length=255, unique=True, description="节点名称")
|
||||
type: int = Field(default=0, sa_column_kwargs={"server_default": "0"}, description="节点类型")
|
||||
server: str = Field(max_length=255, description="节点地址(IP或域名)")
|
||||
slave_key: Optional[str] = Field(default=None, description="从机通讯密钥")
|
||||
master_key: Optional[str] = Field(default=None, description="主机通讯密钥")
|
||||
aria2_enabled: bool = Field(default=False, sa_column_kwargs={"server_default": text("false")}, description="是否启用Aria2")
|
||||
aria2_options: Optional[str] = Field(default=None, description="Aria2配置 (JSON格式)")
|
||||
rank: int = Field(default=0, sa_column_kwargs={"server_default": "0"}, description="节点排序权重")
|
||||
created_at: Optional[datetime] = Field(
|
||||
default=None,
|
||||
sa_column=Column(
|
||||
DateTime,
|
||||
nullable=False,
|
||||
server_default=func.now(),
|
||||
comment="创建时间",
|
||||
),
|
||||
)
|
||||
|
||||
updated_at: Optional[datetime] = Field(
|
||||
default=None,
|
||||
sa_column=Column(
|
||||
DateTime,
|
||||
nullable=False,
|
||||
server_default=func.now(),
|
||||
onupdate=func.now(),
|
||||
comment="更新时间",
|
||||
),
|
||||
)
|
||||
|
||||
# 关系
|
||||
downloads: list["Download"] = Relationship(back_populates="node")
|
||||
47
models/order.py
Normal file
47
models/order.py
Normal file
@@ -0,0 +1,47 @@
|
||||
# my_project/models/order.py
|
||||
|
||||
from typing import Optional, TYPE_CHECKING
|
||||
from sqlmodel import Field, Relationship, Column, func, DateTime
|
||||
from .base import BaseModel
|
||||
from datetime import datetime
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .user import User
|
||||
|
||||
class Order(BaseModel, table=True):
|
||||
__tablename__ = 'orders'
|
||||
|
||||
order_no: str = Field(max_length=255, unique=True, index=True, description="订单号,唯一")
|
||||
type: int = Field(description="订单类型")
|
||||
method: Optional[str] = Field(default=None, max_length=255, description="支付方式")
|
||||
product_id: Optional[int] = Field(default=None, description="商品ID")
|
||||
num: int = Field(default=1, sa_column_kwargs={"server_default": "1"}, description="购买数量")
|
||||
name: str = Field(max_length=255, description="商品名称")
|
||||
price: int = Field(default=0, sa_column_kwargs={"server_default": "0"}, description="订单价格(分)")
|
||||
status: int = Field(default=0, sa_column_kwargs={"server_default": "0"}, description="订单状态: 0=待支付, 1=已完成, 2=已取消")
|
||||
created_at: Optional[datetime] = Field(
|
||||
default=None,
|
||||
sa_column=Column(
|
||||
DateTime,
|
||||
nullable=False,
|
||||
server_default=func.now(),
|
||||
comment="创建时间",
|
||||
),
|
||||
)
|
||||
|
||||
updated_at: Optional[datetime] = Field(
|
||||
default=None,
|
||||
sa_column=Column(
|
||||
DateTime,
|
||||
nullable=False,
|
||||
server_default=func.now(),
|
||||
onupdate=func.now(),
|
||||
comment="更新时间",
|
||||
),
|
||||
)
|
||||
|
||||
# 外键
|
||||
user_id: int = Field(foreign_key="users.id", index=True, description="所属用户ID")
|
||||
|
||||
# 关系
|
||||
user: "User" = Relationship(back_populates="orders")
|
||||
52
models/policy.py
Normal file
52
models/policy.py
Normal file
@@ -0,0 +1,52 @@
|
||||
# my_project/models/policy.py
|
||||
|
||||
from typing import Optional, List, TYPE_CHECKING
|
||||
from sqlmodel import Field, Relationship, text, Column, func, DateTime
|
||||
from .base import BaseModel
|
||||
from datetime import datetime
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .file import File
|
||||
from .folder import Folder
|
||||
|
||||
class Policy(BaseModel, table=True):
|
||||
__tablename__ = 'policies'
|
||||
|
||||
name: str = Field(max_length=255, unique=True, description="策略名称")
|
||||
type: str = Field(max_length=255, description="存储类型 (e.g. 'local', 's3')")
|
||||
server: Optional[str] = Field(default=None, max_length=255, description="服务器地址(本地策略为路径)")
|
||||
bucket_name: Optional[str] = Field(default=None, max_length=255, description="存储桶名称")
|
||||
is_private: bool = Field(default=True, sa_column_kwargs={"server_default": text("true")}, description="是否为私有空间")
|
||||
base_url: Optional[str] = Field(default=None, max_length=255, description="访问文件的基础URL")
|
||||
access_key: Optional[str] = Field(default=None, description="Access Key")
|
||||
secret_key: Optional[str] = Field(default=None, description="Secret Key")
|
||||
max_size: int = Field(default=0, sa_column_kwargs={"server_default": "0"}, description="允许上传的最大文件尺寸(字节)")
|
||||
auto_rename: bool = Field(default=False, sa_column_kwargs={"server_default": text("false")}, description="是否自动重命名")
|
||||
dir_name_rule: Optional[str] = Field(default=None, max_length=255, description="目录命名规则")
|
||||
file_name_rule: Optional[str] = Field(default=None, max_length=255, description="文件命名规则")
|
||||
is_origin_link_enable: bool = Field(default=False, sa_column_kwargs={"server_default": text("false")}, description="是否开启源链接访问")
|
||||
options: Optional[str] = Field(default=None, description="其他选项 (JSON格式)")
|
||||
created_at: Optional[datetime] = Field(
|
||||
default=None,
|
||||
sa_column=Column(
|
||||
DateTime,
|
||||
nullable=False,
|
||||
server_default=func.now(),
|
||||
comment="创建时间",
|
||||
),
|
||||
)
|
||||
|
||||
updated_at: Optional[datetime] = Field(
|
||||
default=None,
|
||||
sa_column=Column(
|
||||
DateTime,
|
||||
nullable=False,
|
||||
server_default=func.now(),
|
||||
onupdate=func.now(),
|
||||
comment="更新时间",
|
||||
),
|
||||
)
|
||||
|
||||
# 关系
|
||||
files: List["File"] = Relationship(back_populates="policy")
|
||||
folders: List["Folder"] = Relationship(back_populates="policy")
|
||||
35
models/redeem.py
Normal file
35
models/redeem.py
Normal file
@@ -0,0 +1,35 @@
|
||||
# my_project/models/redeem.py
|
||||
|
||||
from typing import Optional
|
||||
from sqlmodel import Field, text, Column, func, DateTime
|
||||
from .base import BaseModel
|
||||
from datetime import datetime
|
||||
|
||||
class Redeem(BaseModel, table=True):
|
||||
__tablename__ = 'redeems'
|
||||
|
||||
type: int = Field(description="兑换码类型")
|
||||
product_id: Optional[int] = Field(default=None, description="关联的商品/权益ID")
|
||||
num: int = Field(default=1, sa_column_kwargs={"server_default": "1"}, description="可兑换数量/时长等")
|
||||
code: str = Field(unique=True, index=True, description="兑换码,唯一")
|
||||
used: bool = Field(default=False, sa_column_kwargs={"server_default": text("false")}, description="是否已使用")
|
||||
created_at: Optional[datetime] = Field(
|
||||
default=None,
|
||||
sa_column=Column(
|
||||
DateTime,
|
||||
nullable=False,
|
||||
server_default=func.now(),
|
||||
comment="创建时间",
|
||||
),
|
||||
)
|
||||
|
||||
updated_at: Optional[datetime] = Field(
|
||||
default=None,
|
||||
sa_column=Column(
|
||||
DateTime,
|
||||
nullable=False,
|
||||
server_default=func.now(),
|
||||
onupdate=func.now(),
|
||||
comment="更新时间",
|
||||
),
|
||||
)
|
||||
41
models/report.py
Normal file
41
models/report.py
Normal file
@@ -0,0 +1,41 @@
|
||||
# my_project/models/report.py
|
||||
|
||||
from typing import Optional, TYPE_CHECKING
|
||||
from sqlmodel import Field, Relationship, Column, func, DateTime
|
||||
from .base import BaseModel
|
||||
from datetime import datetime
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .share import Share
|
||||
|
||||
class Report(BaseModel, table=True):
|
||||
__tablename__ = 'reports'
|
||||
|
||||
reason: int = Field(description="举报原因代码")
|
||||
description: Optional[str] = Field(default=None, max_length=255, description="补充描述")
|
||||
created_at: Optional[datetime] = Field(
|
||||
default=None,
|
||||
sa_column=Column(
|
||||
DateTime,
|
||||
nullable=False,
|
||||
server_default=func.now(),
|
||||
comment="创建时间",
|
||||
),
|
||||
)
|
||||
|
||||
updated_at: Optional[datetime] = Field(
|
||||
default=None,
|
||||
sa_column=Column(
|
||||
DateTime,
|
||||
nullable=False,
|
||||
server_default=func.now(),
|
||||
onupdate=func.now(),
|
||||
comment="更新时间",
|
||||
),
|
||||
)
|
||||
|
||||
# 外键
|
||||
share_id: int = Field(foreign_key="shares.id", index=True, description="被举报的分享ID")
|
||||
|
||||
# 关系
|
||||
share: "Share" = Relationship(back_populates="reports")
|
||||
@@ -1,7 +1,20 @@
|
||||
from pydantic import BaseModel, Field
|
||||
from typing import Union, Optional
|
||||
from typing import Literal, Union, Optional
|
||||
from uuid import uuid4
|
||||
|
||||
class ResponseModel(BaseModel):
|
||||
code: int = Field(default=0, description="系统内部状态码, 0表示成功,其他表示失败", lt=60000, gt=0)
|
||||
data: Union[dict, list, str, int, float, None] = Field(None, description="响应数据")
|
||||
msg: Optional[str] = Field(default=None, description="响应消息,可以是错误消息或信息提示")
|
||||
msg: Optional[str] = Field(default=None, description="响应消息,可以是错误消息或信息提示")
|
||||
instance_id: str = Field(default_factory=lambda: str(uuid4()), description="实例ID,用于标识请求的唯一性")
|
||||
|
||||
class SiteConfigModel(ResponseModel):
|
||||
title: str = Field(default="DiskNext", description="网站标题")
|
||||
themes: dict = Field(default_factory=dict, description="网站主题配置")
|
||||
default_theme: str = Field(default="default", description="默认主题RGB色号")
|
||||
site_notice: Optional[str] = Field(default=None, description="网站公告")
|
||||
user: dict = Field(default_factory=dict, description="用户信息")
|
||||
logo_light: Optional[str] = Field(default=None, description="网站Logo URL")
|
||||
logo_dark: Optional[str] = Field(default=None, description="网站Logo URL(深色模式)")
|
||||
captcha_type: Literal['none', 'default', 'gcaptcha', 'cloudflare turnstile'] = Field(default='none', description="验证码类型")
|
||||
captcha_key: Optional[str] = Field(default=None, description="验证码密钥")
|
||||
34
models/setting.py
Normal file
34
models/setting.py
Normal file
@@ -0,0 +1,34 @@
|
||||
# my_project/models/setting.py
|
||||
|
||||
from typing import Optional
|
||||
from sqlmodel import Field, UniqueConstraint, Column, func, DateTime
|
||||
from .base import BaseModel
|
||||
from datetime import datetime
|
||||
|
||||
class Setting(BaseModel, table=True):
|
||||
__tablename__ = 'settings'
|
||||
__table_args__ = (UniqueConstraint("type", "name", name="uq_setting_type_name"),)
|
||||
|
||||
type: str = Field(max_length=255, description="设置类型/分组")
|
||||
name: str = Field(max_length=255, description="设置项名称")
|
||||
value: Optional[str] = Field(default=None, description="设置值")
|
||||
created_at: Optional[datetime] = Field(
|
||||
default=None,
|
||||
sa_column=Column(
|
||||
DateTime,
|
||||
nullable=False,
|
||||
server_default=func.now(),
|
||||
comment="创建时间",
|
||||
),
|
||||
)
|
||||
|
||||
updated_at: Optional[datetime] = Field(
|
||||
default=None,
|
||||
sa_column=Column(
|
||||
DateTime,
|
||||
nullable=False,
|
||||
server_default=func.now(),
|
||||
onupdate=func.now(),
|
||||
comment="更新时间",
|
||||
),
|
||||
)
|
||||
61
models/share.py
Normal file
61
models/share.py
Normal file
@@ -0,0 +1,61 @@
|
||||
# my_project/models/share.py
|
||||
|
||||
from typing import Optional, TYPE_CHECKING
|
||||
from datetime import datetime
|
||||
from sqlmodel import Field, Relationship, text, Column, func, DateTime
|
||||
from .base import BaseModel
|
||||
from datetime import datetime
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .user import User
|
||||
from .report import Report
|
||||
|
||||
class Share(BaseModel, table=True):
|
||||
__tablename__ = 'shares'
|
||||
|
||||
password: Optional[str] = Field(default=None, max_length=255, description="分享密码(加密后)")
|
||||
is_dir: bool = Field(default=False, sa_column_kwargs={"server_default": text("false")}, description="是否为目录分享")
|
||||
source_id: int = Field(description="源文件或目录的ID")
|
||||
views: int = Field(default=0, sa_column_kwargs={"server_default": "0"}, description="浏览次数")
|
||||
downloads: int = Field(default=0, sa_column_kwargs={"server_default": "0"}, description="下载次数")
|
||||
remain_downloads: Optional[int] = Field(default=None, description="剩余下载次数 (NULL为不限制)")
|
||||
expires: Optional[datetime] = Field(default=None, description="过期时间 (NULL为永不过期)")
|
||||
preview_enabled: bool = Field(default=True, sa_column_kwargs={"server_default": text("true")}, description="是否允许预览")
|
||||
source_name: Optional[str] = Field(default=None, max_length=255, index=True, description="源名称(冗余字段,便于展示)")
|
||||
score: int = Field(default=0, sa_column_kwargs={"server_default": "0"}, description="兑换此分享所需的积分")
|
||||
created_at: Optional[datetime] = Field(
|
||||
default=None,
|
||||
sa_column=Column(
|
||||
DateTime,
|
||||
nullable=False,
|
||||
server_default=func.now(),
|
||||
comment="创建时间",
|
||||
),
|
||||
)
|
||||
|
||||
updated_at: Optional[datetime] = Field(
|
||||
default=None,
|
||||
sa_column=Column(
|
||||
DateTime,
|
||||
nullable=False,
|
||||
server_default=func.now(),
|
||||
onupdate=func.now(),
|
||||
comment="更新时间",
|
||||
),
|
||||
)
|
||||
|
||||
delete_at: Optional[datetime] = Field(
|
||||
default=None,
|
||||
sa_column=Column(
|
||||
DateTime,
|
||||
nullable=True,
|
||||
comment="删除时间",
|
||||
),
|
||||
)
|
||||
|
||||
# 外键
|
||||
user_id: int = Field(foreign_key="users.id", index=True, description="创建分享的用户ID")
|
||||
|
||||
# 关系
|
||||
user: "User" = Relationship(back_populates="shares")
|
||||
reports: list["Report"] = Relationship(back_populates="share")
|
||||
50
models/source_link.py
Normal file
50
models/source_link.py
Normal file
@@ -0,0 +1,50 @@
|
||||
# my_project/models/source_link.py
|
||||
|
||||
from typing import TYPE_CHECKING, Optional
|
||||
from sqlmodel import Field, Relationship, Column, func, DateTime
|
||||
from .base import BaseModel
|
||||
from datetime import datetime
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .file import File
|
||||
|
||||
class SourceLink(BaseModel, table=True):
|
||||
__tablename__ = 'source_links'
|
||||
|
||||
name: str = Field(max_length=255, description="链接名称")
|
||||
downloads: int = Field(default=0, sa_column_kwargs={"server_default": "0"}, description="通过此链接的下载次数")
|
||||
created_at: Optional[datetime] = Field(
|
||||
default=None,
|
||||
sa_column=Column(
|
||||
DateTime,
|
||||
nullable=False,
|
||||
server_default=func.now(),
|
||||
comment="创建时间",
|
||||
),
|
||||
)
|
||||
|
||||
updated_at: Optional[datetime] = Field(
|
||||
default=None,
|
||||
sa_column=Column(
|
||||
DateTime,
|
||||
nullable=False,
|
||||
server_default=func.now(),
|
||||
onupdate=func.now(),
|
||||
comment="更新时间",
|
||||
),
|
||||
)
|
||||
|
||||
delete_at: Optional[datetime] = Field(
|
||||
default=None,
|
||||
sa_column=Column(
|
||||
DateTime,
|
||||
nullable=True,
|
||||
comment="删除时间",
|
||||
),
|
||||
)
|
||||
|
||||
# 外键
|
||||
file_id: int = Field(foreign_key="files.id", index=True, description="关联的文件ID")
|
||||
|
||||
# 关系
|
||||
file: "File" = Relationship(back_populates="source_links")
|
||||
52
models/storage_pack.py
Normal file
52
models/storage_pack.py
Normal file
@@ -0,0 +1,52 @@
|
||||
# my_project/models/storage_pack.py
|
||||
|
||||
from typing import Optional, TYPE_CHECKING
|
||||
from datetime import datetime
|
||||
from sqlmodel import Field, Relationship, Column, func, DateTime
|
||||
from .base import BaseModel
|
||||
from datetime import datetime
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .user import User
|
||||
|
||||
class StoragePack(BaseModel, table=True):
|
||||
__tablename__ = 'storage_packs'
|
||||
|
||||
name: str = Field(max_length=255, description="容量包名称")
|
||||
active_time: Optional[datetime] = Field(default=None, description="激活时间")
|
||||
expired_time: Optional[datetime] = Field(default=None, index=True, description="过期时间")
|
||||
size: int = Field(description="容量包大小(字节)")
|
||||
created_at: Optional[datetime] = Field(
|
||||
default=None,
|
||||
sa_column=Column(
|
||||
DateTime,
|
||||
nullable=False,
|
||||
server_default=func.now(),
|
||||
comment="创建时间",
|
||||
),
|
||||
)
|
||||
|
||||
updated_at: Optional[datetime] = Field(
|
||||
default=None,
|
||||
sa_column=Column(
|
||||
DateTime,
|
||||
nullable=False,
|
||||
server_default=func.now(),
|
||||
onupdate=func.now(),
|
||||
comment="更新时间",
|
||||
),
|
||||
)
|
||||
|
||||
delete_at: Optional[datetime] = Field(
|
||||
default=None,
|
||||
sa_column=Column(
|
||||
DateTime,
|
||||
nullable=True,
|
||||
comment="删除时间",
|
||||
),
|
||||
)
|
||||
# 外键
|
||||
user_id: int = Field(foreign_key="users.id", index=True, description="所属用户ID")
|
||||
|
||||
# 关系
|
||||
user: "User" = Relationship(back_populates="storage_packs")
|
||||
54
models/tag.py
Normal file
54
models/tag.py
Normal file
@@ -0,0 +1,54 @@
|
||||
# my_project/models/tag.py
|
||||
|
||||
from typing import Optional, TYPE_CHECKING
|
||||
from sqlmodel import Field, Relationship, UniqueConstraint, Column, func, DateTime
|
||||
from .base import BaseModel
|
||||
from datetime import datetime
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .user import User
|
||||
|
||||
class Tag(BaseModel, table=True):
|
||||
__tablename__ = 'tags'
|
||||
__table_args__ = (UniqueConstraint("name", "user_id", name="uq_tag_name_user"),)
|
||||
|
||||
name: str = Field(max_length=255, description="标签名称")
|
||||
icon: Optional[str] = Field(default=None, max_length=255, description="标签图标")
|
||||
color: Optional[str] = Field(default=None, max_length=255, description="标签颜色")
|
||||
type: int = Field(default=0, sa_column_kwargs={"server_default": "0"}, description="标签类型: 0=手动, 1=自动")
|
||||
expression: Optional[str] = Field(default=None, description="自动标签的匹配表达式")
|
||||
created_at: Optional[datetime] = Field(
|
||||
default=None,
|
||||
sa_column=Column(
|
||||
DateTime,
|
||||
nullable=False,
|
||||
server_default=func.now(),
|
||||
comment="创建时间",
|
||||
),
|
||||
)
|
||||
|
||||
updated_at: Optional[datetime] = Field(
|
||||
default=None,
|
||||
sa_column=Column(
|
||||
DateTime,
|
||||
nullable=False,
|
||||
server_default=func.now(),
|
||||
onupdate=func.now(),
|
||||
comment="更新时间",
|
||||
),
|
||||
)
|
||||
|
||||
delete_at: Optional[datetime] = Field(
|
||||
default=None,
|
||||
sa_column=Column(
|
||||
DateTime,
|
||||
nullable=True,
|
||||
comment="删除时间",
|
||||
),
|
||||
)
|
||||
|
||||
# 外键
|
||||
user_id: int = Field(foreign_key="users.id", index=True, description="所属用户ID")
|
||||
|
||||
# 关系
|
||||
user: "User" = Relationship(back_populates="tags")
|
||||
55
models/task.py
Normal file
55
models/task.py
Normal file
@@ -0,0 +1,55 @@
|
||||
# my_project/models/task.py
|
||||
|
||||
from typing import Optional, TYPE_CHECKING
|
||||
from sqlmodel import Field, Relationship, Column, func, DateTime
|
||||
from .base import BaseModel
|
||||
from datetime import datetime
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .user import User
|
||||
from .download import Download
|
||||
|
||||
class Task(BaseModel, table=True):
|
||||
__tablename__ = 'tasks'
|
||||
|
||||
status: int = Field(default=0, sa_column_kwargs={"server_default": "0"}, description="任务状态: 0=排队中, 1=处理中, 2=完成, 3=错误")
|
||||
type: int = Field(description="任务类型")
|
||||
progress: int = Field(default=0, sa_column_kwargs={"server_default": "0"}, description="任务进度 (0-100)")
|
||||
error: Optional[str] = Field(default=None, description="错误信息")
|
||||
props: Optional[str] = Field(default=None, description="任务属性 (JSON格式)")
|
||||
created_at: Optional[datetime] = Field(
|
||||
default=None,
|
||||
sa_column=Column(
|
||||
DateTime,
|
||||
nullable=False,
|
||||
server_default=func.now(),
|
||||
comment="创建时间",
|
||||
),
|
||||
)
|
||||
|
||||
updated_at: Optional[datetime] = Field(
|
||||
default=None,
|
||||
sa_column=Column(
|
||||
DateTime,
|
||||
nullable=False,
|
||||
server_default=func.now(),
|
||||
onupdate=func.now(),
|
||||
comment="更新时间",
|
||||
),
|
||||
)
|
||||
|
||||
delete_at: Optional[datetime] = Field(
|
||||
default=None,
|
||||
sa_column=Column(
|
||||
DateTime,
|
||||
nullable=True,
|
||||
comment="删除时间",
|
||||
),
|
||||
)
|
||||
|
||||
# 外键
|
||||
user_id: "int" = Field(foreign_key="users.id", index=True, description="所属用户ID")
|
||||
|
||||
# 关系
|
||||
user: "User" = Relationship(back_populates="tasks")
|
||||
downloads: list["Download"] = Relationship(back_populates="task")
|
||||
83
models/user.py
Normal file
83
models/user.py
Normal file
@@ -0,0 +1,83 @@
|
||||
# my_project/models/user.py
|
||||
|
||||
from typing import Optional, TYPE_CHECKING
|
||||
from datetime import datetime
|
||||
from sqlmodel import Field, Relationship, Column, func, DateTime
|
||||
from .base import BaseModel
|
||||
|
||||
# TYPE_CHECKING 用于解决循环导入问题,只在类型检查时导入
|
||||
if TYPE_CHECKING:
|
||||
from .group import Group
|
||||
from .download import Download
|
||||
from .file import File
|
||||
from .folder import Folder
|
||||
from .order import Order
|
||||
from .share import Share
|
||||
from .storage_pack import StoragePack
|
||||
from .tag import Tag
|
||||
from .task import Task
|
||||
from .webdav import WebDAV
|
||||
|
||||
class User(BaseModel, table=True):
|
||||
__tablename__ = 'users'
|
||||
|
||||
email: str = Field(max_length=100, unique=True, index=True, description="用户邮箱,唯一")
|
||||
nick: Optional[str] = Field(default=None, max_length=50, description="用户昵称")
|
||||
password: str = Field(max_length=255, description="用户密码(加密后)")
|
||||
status: int = Field(default=0, sa_column_kwargs={"server_default": "0"}, description="用户状态: 0=正常, 1=未激活, 2=封禁")
|
||||
storage: int = Field(default=0, sa_column_kwargs={"server_default": "0"}, description="已用存储空间(字节)")
|
||||
two_factor: Optional[str] = Field(default=None, max_length=255, description="两步验证密钥")
|
||||
avatar: Optional[str] = Field(default=None, max_length=255, description="头像地址")
|
||||
options: Optional[str] = Field(default=None, description="用户个人设置 (JSON格式)")
|
||||
authn: Optional[str] = Field(default=None, description="WebAuthn 凭证")
|
||||
open_id: Optional[str] = Field(default=None, max_length=255, unique=True, index=True, description="第三方登录OpenID")
|
||||
score: int = Field(default=0, sa_column_kwargs={"server_default": "0"}, description="用户积分")
|
||||
group_expires: Optional[datetime] = Field(default=None, description="当前用户组过期时间")
|
||||
phone: Optional[str] = Field(default=None, max_length=255, unique=True, index=True, description="手机号")
|
||||
created_at: Optional[datetime] = Field(
|
||||
default=None,
|
||||
sa_column=Column(
|
||||
DateTime,
|
||||
nullable=False,
|
||||
server_default=func.now(),
|
||||
comment="创建时间",
|
||||
),
|
||||
)
|
||||
|
||||
updated_at: Optional[datetime] = Field(
|
||||
default=None,
|
||||
sa_column=Column(
|
||||
DateTime,
|
||||
nullable=False,
|
||||
server_default=func.now(),
|
||||
onupdate=func.now(),
|
||||
comment="更新时间",
|
||||
),
|
||||
)
|
||||
|
||||
delete_at: Optional[datetime] = Field(
|
||||
default=None,
|
||||
sa_column=Column(
|
||||
DateTime,
|
||||
nullable=True,
|
||||
comment="删除时间",
|
||||
),
|
||||
)
|
||||
|
||||
# 外键
|
||||
group_id: int = Field(foreign_key="groups.id", index=True, description="所属用户组ID")
|
||||
previous_group_id: Optional[int] = Field(default=None, foreign_key="groups.id", description="之前的用户组ID(用于过期后恢复)")
|
||||
|
||||
# 关系
|
||||
group: "Group" = Relationship(back_populates="users")
|
||||
previous_group: Optional["Group"] = Relationship(back_populates="previous_users")
|
||||
|
||||
downloads: list["Download"] = Relationship(back_populates="user")
|
||||
files: list["File"] = Relationship(back_populates="user")
|
||||
folders: list["Folder"] = Relationship(back_populates="owner")
|
||||
orders: list["Order"] = Relationship(back_populates="user")
|
||||
shares: list["Share"] = Relationship(back_populates="user")
|
||||
storage_packs: list["StoragePack"] = Relationship(back_populates="user")
|
||||
tags: list["Tag"] = Relationship(back_populates="user")
|
||||
tasks: list["Task"] = Relationship(back_populates="user")
|
||||
webdavs: list["WebDAV"] = Relationship(back_populates="user")
|
||||
54
models/webdav.py
Normal file
54
models/webdav.py
Normal file
@@ -0,0 +1,54 @@
|
||||
# my_project/models/webdav.py
|
||||
|
||||
from typing import Optional, TYPE_CHECKING
|
||||
from sqlmodel import Field, Relationship, UniqueConstraint, text, Column, func, DateTime
|
||||
from .base import BaseModel
|
||||
from datetime import datetime
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .user import User
|
||||
|
||||
class WebDAV(BaseModel, table=True):
|
||||
__tablename__ = 'webdavs'
|
||||
__table_args__ = (UniqueConstraint("name", "user_id", name="uq_webdav_name_user"),)
|
||||
|
||||
name: str = Field(max_length=255, description="WebDAV账户名")
|
||||
password: str = Field(max_length=255, description="WebDAV密码(加密后)")
|
||||
root: str = Field(default="/", sa_column_kwargs={"server_default": "'/'"}, description="根目录路径")
|
||||
readonly: bool = Field(default=False, sa_column_kwargs={"server_default": text("false")}, description="是否只读")
|
||||
use_proxy: bool = Field(default=False, sa_column_kwargs={"server_default": text("false")}, description="是否使用代理下载")
|
||||
created_at: Optional[datetime] = Field(
|
||||
default=None,
|
||||
sa_column=Column(
|
||||
DateTime,
|
||||
nullable=False,
|
||||
server_default=func.now(),
|
||||
comment="创建时间",
|
||||
),
|
||||
)
|
||||
|
||||
updated_at: Optional[datetime] = Field(
|
||||
default=None,
|
||||
sa_column=Column(
|
||||
DateTime,
|
||||
nullable=False,
|
||||
server_default=func.now(),
|
||||
onupdate=func.now(),
|
||||
comment="更新时间",
|
||||
),
|
||||
)
|
||||
|
||||
delete_at: Optional[datetime] = Field(
|
||||
default=None,
|
||||
sa_column=Column(
|
||||
DateTime,
|
||||
nullable=True,
|
||||
comment="删除时间",
|
||||
),
|
||||
)
|
||||
|
||||
# 外键
|
||||
user_id: int = Field(foreign_key="users.id", index=True, description="所属用户ID")
|
||||
|
||||
# 关系
|
||||
user: "User" = Relationship(back_populates="webdavs")
|
||||
Reference in New Issue
Block a user