feat: 重构主题相关逻辑,移动 ThemeResponse 到 color.py,更新相关引用,优化目录路径处理

This commit is contained in:
2025-12-19 15:35:34 +08:00
parent 20753f1725
commit e031f3cc40
6 changed files with 60 additions and 55 deletions

View File

@@ -2,7 +2,6 @@ from . import response
from .user import ( from .user import (
LoginRequest, LoginRequest,
ThemeResponse,
TokenResponse, TokenResponse,
User, User,
UserBase, UserBase,
@@ -12,6 +11,7 @@ from .user import (
WebAuthnInfo, WebAuthnInfo,
) )
from .user_authn import AuthnResponse, UserAuthn from .user_authn import AuthnResponse, UserAuthn
from .color import ThemeResponse
from .download import Download from .download import Download
from .group import Group, GroupBase, GroupOptionsBase, GroupResponse from .group import Group, GroupBase, GroupOptionsBase, GroupResponse

31
models/color.py Normal file
View File

@@ -0,0 +1,31 @@
from .base import SQLModelBase
class ThemeResponse(SQLModelBase):
"""主题响应 DTO"""
primary: str = "#3f51b5"
"""主色调"""
secondary: str = "#f50057"
"""次要色"""
accent: str = "#9c27b0"
"""强调色"""
dark: str = "#1d1d1d"
"""深色"""
dark_page: str = "#121212"
"""深色页面背景"""
positive: str = "#21ba45"
"""正面/成功色"""
negative: str = "#c10015"
"""负面/错误色"""
info: str = "#31ccec"
"""信息色"""
warning: str = "#f2c037"
"""警告色"""

View File

@@ -1,6 +1,6 @@
from .setting import Setting, SettingsType from .setting import Setting, SettingsType
from .user import ThemeResponse from .color import ThemeResponse
from pkg.conf.appmeta import BackendVersion from pkg.conf.appmeta import BackendVersion
from pkg.password.pwd import Password from pkg.password.pwd import Password
from loguru import logger as log from loguru import logger as log
@@ -225,7 +225,7 @@ async def init_default_user() -> None:
# 为管理员创建根目录(使用默认存储策略) # 为管理员创建根目录(使用默认存储策略)
await Object( await Object(
name="~", name="my",
type=ObjectType.FOLDER, type=ObjectType.FOLDER,
owner_id=admin_user.id, owner_id=admin_user.id,
parent_id=None, parent_id=None,

View File

@@ -110,7 +110,7 @@ class Object(ObjectBase, TableBase, table=True):
合并了原有的 File 和 Folder 模型,通过 type 字段区分文件和目录。 合并了原有的 File 和 Folder 模型,通过 type 字段区分文件和目录。
根目录规则: 根目录规则:
- 每个用户有一个显式根目录对象name="~", parent_id=NULL - 每个用户有一个显式根目录对象name="my", parent_id=NULL
- 用户创建的文件/文件夹的 parent_id 指向根目录或其他文件夹的 id - 用户创建的文件/文件夹的 parent_id 指向根目录或其他文件夹的 id
- 根目录的 policy_id 指定用户默认存储策略 - 根目录的 policy_id 指定用户默认存储策略
""" """
@@ -138,6 +138,9 @@ class Object(ObjectBase, TableBase, table=True):
type: ObjectType type: ObjectType
"""对象类型file 或 folder""" """对象类型file 或 folder"""
password: str | None = Field(default=None, max_length=255)
"""对象独立密码(仅当用户为对象单独设置密码时有效)"""
# ==================== 文件专属字段 ==================== # ==================== 文件专属字段 ====================
source_name: str | None = None source_name: str | None = None
@@ -149,6 +152,7 @@ class Object(ObjectBase, TableBase, table=True):
upload_session_id: str | None = Field(default=None, max_length=255, unique=True, index=True) upload_session_id: str | None = Field(default=None, max_length=255, unique=True, index=True)
"""分块上传会话ID仅文件有效""" """分块上传会话ID仅文件有效"""
# [TODO] 拆分
file_metadata: str | None = None file_metadata: str | None = None
"""文件元数据 (JSON格式),仅文件有效""" """文件元数据 (JSON格式),仅文件有效"""
@@ -227,7 +231,10 @@ class Object(ObjectBase, TableBase, table=True):
:return: Object 或 None :return: Object 或 None
""" """
path = path.strip() path = path.strip()
if not path or path == "/" or path == "~": if not path:
raise ValueError("路径不能为空")
if path in ["/my"]:
return await cls.get_root(session, user_id) return await cls.get_root(session, user_id)
# 移除开头的斜杠并分割路径 # 移除开头的斜杠并分割路径

View File

@@ -34,6 +34,13 @@ class AvatarType(StrEnum):
GRAVATAR = "gravatar" GRAVATAR = "gravatar"
FILE = "file" FILE = "file"
class ThemeType(StrEnum):
"""主题类型枚举"""
LIGHT = "light"
DARK = "dark"
SYSTEM = "system"
# ==================== Base 模型 ==================== # ==================== Base 模型 ====================
@@ -90,37 +97,6 @@ class WebAuthnInfo(SQLModelBase):
"""支持的传输方式""" """支持的传输方式"""
class ThemeResponse(SQLModelBase):
"""主题响应 DTO"""
primary: str = "#3f51b5"
"""主色调"""
secondary: str = "#f50057"
"""次要色"""
accent: str = "#9c27b0"
"""强调色"""
dark: str = "#1d1d1d"
"""深色"""
dark_page: str = "#121212"
"""深色页面背景"""
positive: str = "#21ba45"
"""正面/成功色"""
negative: str = "#c10015"
"""负面/错误色"""
info: str = "#31ccec"
"""信息色"""
warning: str = "#f2c037"
"""警告色"""
class TokenResponse(SQLModelBase): class TokenResponse(SQLModelBase):
"""访问令牌响应 DTO""" """访问令牌响应 DTO"""
@@ -152,9 +128,6 @@ class UserResponse(UserBase):
created_at: datetime created_at: datetime
"""用户创建时间""" """用户创建时间"""
preferred_theme: ThemeResponse | None = None
"""用户首选主题"""
anonymous: bool = False anonymous: bool = False
"""是否为匿名用户""" """是否为匿名用户"""
@@ -253,23 +226,21 @@ class User(UserBase, TableBase, table=True):
avatar: str = Field(default="default", max_length=255) avatar: str = Field(default="default", max_length=255)
"""头像地址""" """头像地址"""
options: str | None = None
"""[TODO] 用户个人设置 需要更改,参考上方的需求"""
github_open_id: str | None = Field(default=None, unique=True, index=True)
"""Github OpenID"""
qq_open_id: str | None = Field(default=None, unique=True, index=True)
"""QQ OpenID"""
score: int = Field(default=0, sa_column_kwargs={"server_default": "0"}, ge=0) score: int = Field(default=0, sa_column_kwargs={"server_default": "0"}, ge=0)
"""用户积分""" """用户积分"""
group_expires: datetime | None = None group_expires: datetime | None = None
"""当前用户组过期时间""" """当前用户组过期时间"""
phone: str | None = Field(default=None, max_length=32, unique=True, index=True) # Option 相关字段
"""手机号""" theme: ThemeType = Field(default=ThemeType.SYSTEM, sa_column_kwargs={"server_default": "system"})
"""主题类型: light/dark/system"""
language: str = Field(default="zh-CN", max_length=5, sa_column_kwargs={"server_default": "zh-CN"})
"""语言偏好"""
timezone: int = Field(default=8, ge=-12, le=12, sa_column_kwargs={"server_default": "8"})
"""时区UTC 偏移小时数"""
# 外键 # 外键
group_id: int = Field(foreign_key="group.id", index=True) group_id: int = Field(foreign_key="group.id", index=True)
@@ -278,7 +249,6 @@ class User(UserBase, TableBase, table=True):
previous_group_id: int | None = Field(default=None, foreign_key="group.id") previous_group_id: int | None = Field(default=None, foreign_key="group.id")
"""之前的用户组ID用于过期后恢复""" """之前的用户组ID用于过期后恢复"""
# [TODO] 待考虑:根目录 Object ID
# 关系 # 关系
group: "Group" = Relationship( group: "Group" = Relationship(

View File

@@ -34,7 +34,7 @@ async def router_directory_get(
:param session: 数据库会话 :param session: 数据库会话
:param user: 当前登录用户 :param user: 当前登录用户
:param path: 目录路径 "~" 表示根目录 :param path: 目录路径
:return: 目录内容 :return: 目录内容
""" """
folder = await Object.get_by_path(session, user.id, path or "/") folder = await Object.get_by_path(session, user.id, path or "/")
@@ -45,9 +45,6 @@ async def router_directory_get(
if not folder.is_folder: if not folder.is_folder:
raise HTTPException(status_code=400, detail="指定路径不是目录") raise HTTPException(status_code=400, detail="指定路径不是目录")
if path != "~":
path = path.lstrip("~")
children = await Object.get_children(session, user.id, folder.id) children = await Object.get_children(session, user.id, folder.id)
policy = await folder.awaitable_attrs.policy policy = await folder.awaitable_attrs.policy