feat: add models for physical files, policies, and user management

- Implement PhysicalFile model to manage physical file references and reference counting.
- Create Policy model with associated options and group links for storage policies.
- Introduce Redeem and Report models for handling redeem codes and reports.
- Add Settings model for site configuration and user settings management.
- Develop Share model for sharing objects with unique codes and associated metadata.
- Implement SourceLink model for managing download links associated with objects.
- Create StoragePack model for managing user storage packages.
- Add Tag model for user-defined tags with manual and automatic types.
- Implement Task model for managing background tasks with status tracking.
- Develop User model with comprehensive user management features including authentication.
- Introduce UserAuthn model for managing WebAuthn credentials.
- Create WebDAV model for managing WebDAV accounts associated with users.
This commit is contained in:
2026-02-10 16:25:49 +08:00
parent 62c671e07b
commit 209cb24ab4
92 changed files with 3640 additions and 1444 deletions

View File

@@ -8,8 +8,8 @@ import pytest
from fastapi import HTTPException
from sqlmodel.ext.asyncio.session import AsyncSession
from models.user import User
from models.group import Group
from sqlmodels.user import User
from sqlmodels.group import Group
@pytest.mark.asyncio
@@ -62,7 +62,7 @@ async def test_table_base_update(db_session: AsyncSession):
group = await group.save(db_session)
# 更新数据
from models.group import GroupBase
from sqlmodels.group import GroupBase
update_data = GroupBase(name="更新后名称")
updated_group = await group.update(db_session, update_data)
@@ -200,7 +200,7 @@ async def test_timestamps_auto_update(db_session: AsyncSession):
await asyncio.sleep(0.1)
# 更新记录
from models.group import GroupBase
from sqlmodels.group import GroupBase
update_data = GroupBase(name="更新后的名称")
group = await group.update(db_session, update_data)

View File

@@ -4,7 +4,7 @@ Group 和 GroupOptions 模型的单元测试
import pytest
from sqlmodel.ext.asyncio.session import AsyncSession
from models.group import Group, GroupOptions, GroupResponse
from sqlmodels.group import Group, GroupOptions, GroupResponse
@pytest.mark.asyncio

View File

@@ -5,21 +5,21 @@ import pytest
from sqlalchemy.exc import IntegrityError
from sqlmodel.ext.asyncio.session import AsyncSession
from models.object import Object, ObjectType
from models.user import User
from models.group import Group
from sqlmodels.object import Object, ObjectType
from sqlmodels.user import User
from sqlmodels.group import Group
@pytest.mark.asyncio
async def test_object_create_folder(db_session: AsyncSession):
"""测试创建目录"""
# 创建必要的依赖数据
from models.policy import Policy, PolicyType
from sqlmodels.policy import Policy, PolicyType
group = Group(name="测试组")
group = await group.save(db_session)
user = User(username="testuser", password="password", group_id=group.id)
user = User(email="testuser", password="password", group_id=group.id)
user = await user.save(db_session)
policy = Policy(
@@ -48,12 +48,12 @@ async def test_object_create_folder(db_session: AsyncSession):
@pytest.mark.asyncio
async def test_object_create_file(db_session: AsyncSession):
"""测试创建文件"""
from models.policy import Policy, PolicyType
from sqlmodels.policy import Policy, PolicyType
group = Group(name="测试组")
group = await group.save(db_session)
user = User(username="testuser", password="password", group_id=group.id)
user = User(email="testuser", password="password", group_id=group.id)
user = await user.save(db_session)
policy = Policy(
@@ -65,7 +65,7 @@ async def test_object_create_file(db_session: AsyncSession):
# 创建根目录
root = Object(
name=user.username,
name="/",
type=ObjectType.FOLDER,
parent_id=None,
owner_id=user.id,
@@ -81,7 +81,6 @@ async def test_object_create_file(db_session: AsyncSession):
owner_id=user.id,
policy_id=policy.id,
size=1024,
source_name="test_source.txt"
)
file = await file.save(db_session)
@@ -89,18 +88,17 @@ async def test_object_create_file(db_session: AsyncSession):
assert file.name == "test.txt"
assert file.type == ObjectType.FILE
assert file.size == 1024
assert file.source_name == "test_source.txt"
@pytest.mark.asyncio
async def test_object_is_file_property(db_session: AsyncSession):
"""测试 is_file 属性"""
from models.policy import Policy, PolicyType
from sqlmodels.policy import Policy, PolicyType
group = Group(name="测试组")
group = await group.save(db_session)
user = User(username="testuser", password="password", group_id=group.id)
user = User(email="testuser", password="password", group_id=group.id)
user = await user.save(db_session)
policy = Policy(name="本地策略", type=PolicyType.LOCAL, server="/tmp/test")
@@ -122,12 +120,12 @@ async def test_object_is_file_property(db_session: AsyncSession):
@pytest.mark.asyncio
async def test_object_is_folder_property(db_session: AsyncSession):
"""测试 is_folder 属性"""
from models.policy import Policy, PolicyType
from sqlmodels.policy import Policy, PolicyType
group = Group(name="测试组")
group = await group.save(db_session)
user = User(username="testuser", password="password", group_id=group.id)
user = User(email="testuser", password="password", group_id=group.id)
user = await user.save(db_session)
policy = Policy(name="本地策略", type=PolicyType.LOCAL, server="/tmp/test")
@@ -148,12 +146,12 @@ async def test_object_is_folder_property(db_session: AsyncSession):
@pytest.mark.asyncio
async def test_object_get_root(db_session: AsyncSession):
"""测试 get_root() 方法"""
from models.policy import Policy, PolicyType
from sqlmodels.policy import Policy, PolicyType
group = Group(name="测试组")
group = await group.save(db_session)
user = User(username="rootuser", password="password", group_id=group.id)
user = User(email="rootuser", password="password", group_id=group.id)
user = await user.save(db_session)
policy = Policy(name="本地策略", type=PolicyType.LOCAL, server="/tmp/test")
@@ -161,7 +159,7 @@ async def test_object_get_root(db_session: AsyncSession):
# 创建根目录
root = Object(
name=user.username,
name="/",
type=ObjectType.FOLDER,
parent_id=None,
owner_id=user.id,
@@ -180,12 +178,12 @@ async def test_object_get_root(db_session: AsyncSession):
@pytest.mark.asyncio
async def test_object_get_by_path_root(db_session: AsyncSession):
"""测试获取根目录"""
from models.policy import Policy, PolicyType
from sqlmodels.policy import Policy, PolicyType
group = Group(name="测试组")
group = await group.save(db_session)
user = User(username="pathuser", password="password", group_id=group.id)
user = User(email="pathuser", password="password", group_id=group.id)
user = await user.save(db_session)
policy = Policy(name="本地策略", type=PolicyType.LOCAL, server="/tmp/test")
@@ -193,7 +191,7 @@ async def test_object_get_by_path_root(db_session: AsyncSession):
# 创建根目录
root = Object(
name=user.username,
name="/",
type=ObjectType.FOLDER,
parent_id=None,
owner_id=user.id,
@@ -202,7 +200,7 @@ async def test_object_get_by_path_root(db_session: AsyncSession):
root = await root.save(db_session)
# 通过路径获取根目录
result = await Object.get_by_path(db_session, user.id, "/pathuser", user.username)
result = await Object.get_by_path(db_session, user.id, "/")
assert result is not None
assert result.id == root.id
@@ -211,12 +209,12 @@ async def test_object_get_by_path_root(db_session: AsyncSession):
@pytest.mark.asyncio
async def test_object_get_by_path_nested(db_session: AsyncSession):
"""测试获取嵌套路径"""
from models.policy import Policy, PolicyType
from sqlmodels.policy import Policy, PolicyType
group = Group(name="测试组")
group = await group.save(db_session)
user = User(username="nesteduser", password="password", group_id=group.id)
user = User(email="nesteduser", password="password", group_id=group.id)
user = await user.save(db_session)
policy = Policy(name="本地策略", type=PolicyType.LOCAL, server="/tmp/test")
@@ -224,7 +222,7 @@ async def test_object_get_by_path_nested(db_session: AsyncSession):
# 创建目录结构: root -> docs -> work -> project
root = Object(
name=user.username,
name="/",
type=ObjectType.FOLDER,
parent_id=None,
owner_id=user.id,
@@ -263,8 +261,7 @@ async def test_object_get_by_path_nested(db_session: AsyncSession):
result = await Object.get_by_path(
db_session,
user.id,
"/nesteduser/docs/work/project",
user.username
"/docs/work/project",
)
assert result is not None
@@ -275,12 +272,12 @@ async def test_object_get_by_path_nested(db_session: AsyncSession):
@pytest.mark.asyncio
async def test_object_get_by_path_not_found(db_session: AsyncSession):
"""测试路径不存在"""
from models.policy import Policy, PolicyType
from sqlmodels.policy import Policy, PolicyType
group = Group(name="测试组")
group = await group.save(db_session)
user = User(username="notfounduser", password="password", group_id=group.id)
user = User(email="notfounduser", password="password", group_id=group.id)
user = await user.save(db_session)
policy = Policy(name="本地策略", type=PolicyType.LOCAL, server="/tmp/test")
@@ -288,7 +285,7 @@ async def test_object_get_by_path_not_found(db_session: AsyncSession):
# 创建根目录
root = Object(
name=user.username,
name="/",
type=ObjectType.FOLDER,
parent_id=None,
owner_id=user.id,
@@ -300,8 +297,7 @@ async def test_object_get_by_path_not_found(db_session: AsyncSession):
result = await Object.get_by_path(
db_session,
user.id,
"/notfounduser/nonexistent",
user.username
"/nonexistent",
)
assert result is None
@@ -310,12 +306,12 @@ async def test_object_get_by_path_not_found(db_session: AsyncSession):
@pytest.mark.asyncio
async def test_object_get_children(db_session: AsyncSession):
"""测试 get_children() 方法"""
from models.policy import Policy, PolicyType
from sqlmodels.policy import Policy, PolicyType
group = Group(name="测试组")
group = await group.save(db_session)
user = User(username="childrenuser", password="password", group_id=group.id)
user = User(email="childrenuser", password="password", group_id=group.id)
user = await user.save(db_session)
policy = Policy(name="本地策略", type=PolicyType.LOCAL, server="/tmp/test")
@@ -362,12 +358,12 @@ async def test_object_get_children(db_session: AsyncSession):
@pytest.mark.asyncio
async def test_object_parent_child_relationship(db_session: AsyncSession):
"""测试父子关系"""
from models.policy import Policy, PolicyType
from sqlmodels.policy import Policy, PolicyType
group = Group(name="测试组")
group = await group.save(db_session)
user = User(username="reluser", password="password", group_id=group.id)
user = User(email="reluser", password="password", group_id=group.id)
user = await user.save(db_session)
policy = Policy(name="本地策略", type=PolicyType.LOCAL, server="/tmp/test")
@@ -407,12 +403,12 @@ async def test_object_parent_child_relationship(db_session: AsyncSession):
@pytest.mark.asyncio
async def test_object_unique_constraint(db_session: AsyncSession):
"""测试同目录名称唯一约束"""
from models.policy import Policy, PolicyType
from sqlmodels.policy import Policy, PolicyType
group = Group(name="测试组")
group = await group.save(db_session)
user = User(username="uniqueuser", password="password", group_id=group.id)
user = User(email="uniqueuser", password="password", group_id=group.id)
user = await user.save(db_session)
policy = Policy(name="本地策略", type=PolicyType.LOCAL, server="/tmp/test")
@@ -450,3 +446,64 @@ async def test_object_unique_constraint(db_session: AsyncSession):
with pytest.raises(IntegrityError):
await file2.save(db_session)
@pytest.mark.asyncio
async def test_object_get_full_path(db_session: AsyncSession):
"""测试 get_full_path() 方法"""
from sqlmodels.policy import Policy, PolicyType
group = Group(name="测试组")
group = await group.save(db_session)
user = User(email="pathuser", password="password", group_id=group.id)
user = await user.save(db_session)
policy = Policy(name="本地策略", type=PolicyType.LOCAL, server="/tmp/test")
policy = await policy.save(db_session)
# 创建目录结构: root -> docs -> images -> photo.jpg
root = Object(
name="/",
type=ObjectType.FOLDER,
parent_id=None,
owner_id=user.id,
policy_id=policy.id
)
root = await root.save(db_session)
docs = Object(
name="docs",
type=ObjectType.FOLDER,
parent_id=root.id,
owner_id=user.id,
policy_id=policy.id
)
docs = await docs.save(db_session)
images = Object(
name="images",
type=ObjectType.FOLDER,
parent_id=docs.id,
owner_id=user.id,
policy_id=policy.id
)
images = await images.save(db_session)
photo = Object(
name="photo.jpg",
type=ObjectType.FILE,
parent_id=images.id,
owner_id=user.id,
policy_id=policy.id,
size=2048
)
photo = await photo.save(db_session)
# 测试完整路径
full_path = await photo.get_full_path(db_session)
assert full_path == "/docs/images/photo.jpg"
# 测试根目录的 full_path
root_path = await root.get_full_path(db_session)
assert root_path == "/"

View File

@@ -5,7 +5,7 @@ import pytest
from sqlalchemy.exc import IntegrityError
from sqlmodel.ext.asyncio.session import AsyncSession
from models.setting import Setting, SettingsType
from sqlmodels.setting import Setting, SettingsType
@pytest.mark.asyncio
@@ -113,7 +113,7 @@ async def test_setting_update_value(db_session: AsyncSession):
setting = await setting.save(db_session)
# 更新值
from models.base import SQLModelBase
from sqlmodels.base import SQLModelBase
class SettingUpdate(SQLModelBase):
value: str | None = None

View File

@@ -0,0 +1,273 @@
"""
DiskNextURI 模型的单元测试
"""
import pytest
from sqlmodels.uri import DiskNextURI, FileSystemNamespace
class TestDiskNextURIParse:
"""测试 URI 解析"""
def test_parse_my_root(self):
"""测试解析个人空间根目录"""
uri = DiskNextURI.parse("disknext://my/")
assert uri.namespace == FileSystemNamespace.MY
assert uri.path == "/"
assert uri.fs_id is None
assert uri.password is None
assert uri.is_root is True
def test_parse_my_with_path(self):
"""测试解析个人空间带路径"""
uri = DiskNextURI.parse("disknext://my/docs/readme.md")
assert uri.namespace == FileSystemNamespace.MY
assert uri.path == "/docs/readme.md"
assert uri.fs_id is None
assert uri.path_parts == ["docs", "readme.md"]
assert uri.is_root is False
def test_parse_my_with_fs_id(self):
"""测试解析带 fs_id 的个人空间"""
uri = DiskNextURI.parse("disknext://some-uuid@my/docs")
assert uri.namespace == FileSystemNamespace.MY
assert uri.fs_id == "some-uuid"
assert uri.path == "/docs"
def test_parse_share_with_code(self):
"""测试解析分享链接"""
uri = DiskNextURI.parse("disknext://abc123@share/")
assert uri.namespace == FileSystemNamespace.SHARE
assert uri.fs_id == "abc123"
assert uri.path == "/"
assert uri.password is None
def test_parse_share_with_password(self):
"""测试解析带密码的分享链接"""
uri = DiskNextURI.parse("disknext://abc123:mypass@share/sub/dir")
assert uri.namespace == FileSystemNamespace.SHARE
assert uri.fs_id == "abc123"
assert uri.password == "mypass"
assert uri.path == "/sub/dir"
def test_parse_trash(self):
"""测试解析回收站"""
uri = DiskNextURI.parse("disknext://trash/")
assert uri.namespace == FileSystemNamespace.TRASH
assert uri.is_root is True
def test_parse_with_query(self):
"""测试解析带查询参数的 URI"""
uri = DiskNextURI.parse("disknext://my/?name=report&type=file")
assert uri.namespace == FileSystemNamespace.MY
assert uri.query is not None
assert uri.query["name"] == "report"
assert uri.query["type"] == "file"
def test_parse_invalid_scheme(self):
"""测试无效的协议前缀"""
with pytest.raises(ValueError, match="disknext://"):
DiskNextURI.parse("http://my/docs")
def test_parse_invalid_namespace(self):
"""测试无效的命名空间"""
with pytest.raises(ValueError, match="无效的命名空间"):
DiskNextURI.parse("disknext://invalid/docs")
def test_parse_no_namespace(self):
"""测试缺少命名空间"""
with pytest.raises(ValueError):
DiskNextURI.parse("disknext://")
class TestDiskNextURIBuild:
"""测试 URI 构建"""
def test_build_simple(self):
"""测试简单构建"""
uri = DiskNextURI.build(FileSystemNamespace.MY)
assert uri.namespace == FileSystemNamespace.MY
assert uri.path == "/"
assert uri.fs_id is None
def test_build_with_path(self):
"""测试带路径构建"""
uri = DiskNextURI.build(FileSystemNamespace.MY, path="/docs/readme.md")
assert uri.path == "/docs/readme.md"
def test_build_path_auto_prefix(self):
"""测试路径自动添加 / 前缀"""
uri = DiskNextURI.build(FileSystemNamespace.MY, path="docs/readme.md")
assert uri.path == "/docs/readme.md"
def test_build_with_fs_id(self):
"""测试带 fs_id 构建"""
uri = DiskNextURI.build(
FileSystemNamespace.SHARE,
fs_id="abc123",
password="secret",
)
assert uri.fs_id == "abc123"
assert uri.password == "secret"
class TestDiskNextURIToString:
"""测试 URI 序列化"""
def test_to_string_simple(self):
"""测试简单序列化"""
uri = DiskNextURI.build(FileSystemNamespace.MY)
assert uri.to_string() == "disknext://my/"
def test_to_string_with_path(self):
"""测试带路径序列化"""
uri = DiskNextURI.build(FileSystemNamespace.MY, path="/docs/readme.md")
assert uri.to_string() == "disknext://my/docs/readme.md"
def test_to_string_with_fs_id(self):
"""测试带 fs_id 序列化"""
uri = DiskNextURI.build(FileSystemNamespace.MY, fs_id="uuid-123")
assert uri.to_string() == "disknext://uuid-123@my/"
def test_to_string_with_password(self):
"""测试带密码序列化"""
uri = DiskNextURI.build(
FileSystemNamespace.SHARE,
fs_id="code",
password="pass",
)
assert uri.to_string() == "disknext://code:pass@share/"
def test_to_string_roundtrip(self):
"""测试序列化-反序列化往返"""
original = "disknext://abc123:pass@share/sub/dir"
uri = DiskNextURI.parse(original)
result = uri.to_string()
assert result == original
class TestDiskNextURIId:
"""测试 id() 方法"""
def test_id_with_fs_id(self):
"""测试有 fs_id 时返回 fs_id"""
uri = DiskNextURI.build(FileSystemNamespace.MY, fs_id="my-uuid")
assert uri.id("default") == "my-uuid"
def test_id_without_fs_id(self):
"""测试无 fs_id 时返回默认值"""
uri = DiskNextURI.build(FileSystemNamespace.MY)
assert uri.id("default-uuid") == "default-uuid"
def test_id_without_fs_id_no_default(self):
"""测试无 fs_id 且无默认值时返回 None"""
uri = DiskNextURI.build(FileSystemNamespace.MY)
assert uri.id() is None
class TestDiskNextURIJoin:
"""测试 join() 方法"""
def test_join_single(self):
"""测试拼接单个路径元素"""
uri = DiskNextURI.build(FileSystemNamespace.MY, path="/docs")
joined = uri.join("readme.md")
assert joined.path == "/docs/readme.md"
def test_join_multiple(self):
"""测试拼接多个路径元素"""
uri = DiskNextURI.build(FileSystemNamespace.MY)
joined = uri.join("docs", "work", "report.pdf")
assert joined.path == "/docs/work/report.pdf"
def test_join_preserves_metadata(self):
"""测试 join 保留 namespace 和 fs_id"""
uri = DiskNextURI.build(FileSystemNamespace.SHARE, fs_id="code123")
joined = uri.join("sub")
assert joined.namespace == FileSystemNamespace.SHARE
assert joined.fs_id == "code123"
class TestDiskNextURIDirUri:
"""测试 dir_uri() 方法"""
def test_dir_uri_file(self):
"""测试获取文件的父目录 URI"""
uri = DiskNextURI.build(FileSystemNamespace.MY, path="/docs/readme.md")
parent = uri.dir_uri()
assert parent.path == "/docs/"
def test_dir_uri_root(self):
"""测试根目录的 dir_uri 返回自身"""
uri = DiskNextURI.build(FileSystemNamespace.MY, path="/")
parent = uri.dir_uri()
assert parent.path == "/"
class TestDiskNextURIRoot:
"""测试 root() 方法"""
def test_root_resets_path(self):
"""测试 root 重置路径"""
uri = DiskNextURI.build(
FileSystemNamespace.MY,
path="/docs/work/report.pdf",
fs_id="uuid-123",
)
root = uri.root()
assert root.path == "/"
assert root.fs_id == "uuid-123"
assert root.namespace == FileSystemNamespace.MY
class TestDiskNextURIName:
"""测试 name() 方法"""
def test_name_file(self):
"""测试获取文件名"""
uri = DiskNextURI.build(FileSystemNamespace.MY, path="/docs/readme.md")
assert uri.name() == "readme.md"
def test_name_directory(self):
"""测试获取目录名"""
uri = DiskNextURI.build(FileSystemNamespace.MY, path="/docs/work")
assert uri.name() == "work"
def test_name_root(self):
"""测试根目录的 name 返回空字符串"""
uri = DiskNextURI.build(FileSystemNamespace.MY, path="/")
assert uri.name() == ""
class TestDiskNextURIProperties:
"""测试属性方法"""
def test_path_parts(self):
"""测试路径分割"""
uri = DiskNextURI.build(FileSystemNamespace.MY, path="/docs/work/report.pdf")
assert uri.path_parts == ["docs", "work", "report.pdf"]
def test_path_parts_root(self):
"""测试根路径分割"""
uri = DiskNextURI.build(FileSystemNamespace.MY, path="/")
assert uri.path_parts == []
def test_is_root_true(self):
"""测试 is_root 为真"""
uri = DiskNextURI.build(FileSystemNamespace.MY, path="/")
assert uri.is_root is True
def test_is_root_false(self):
"""测试 is_root 为假"""
uri = DiskNextURI.build(FileSystemNamespace.MY, path="/docs")
assert uri.is_root is False
def test_str_representation(self):
"""测试字符串表示"""
uri = DiskNextURI.build(FileSystemNamespace.MY, path="/docs")
assert str(uri) == "disknext://my/docs"
def test_repr(self):
"""测试 repr"""
uri = DiskNextURI.build(FileSystemNamespace.MY, path="/docs")
assert "disknext://my/docs" in repr(uri)

View File

@@ -5,8 +5,8 @@ import pytest
from sqlalchemy.exc import IntegrityError
from sqlmodel.ext.asyncio.session import AsyncSession
from models.user import User, ThemeType, UserPublic
from models.group import Group
from sqlmodels.user import User, ThemeType, UserPublic
from sqlmodels.group import Group
@pytest.mark.asyncio
@@ -18,7 +18,7 @@ async def test_user_create(db_session: AsyncSession):
# 创建用户
user = User(
username="testuser",
email="testuser@test.local",
nickname="测试用户",
password="hashed_password",
group_id=group.id
@@ -26,7 +26,7 @@ async def test_user_create(db_session: AsyncSession):
user = await user.save(db_session)
assert user.id is not None
assert user.username == "testuser"
assert user.email == "testuser@test.local"
assert user.nickname == "测试用户"
assert user.status is True
assert user.storage == 0
@@ -34,15 +34,15 @@ async def test_user_create(db_session: AsyncSession):
@pytest.mark.asyncio
async def test_user_unique_username(db_session: AsyncSession):
"""测试用户名唯一约束"""
async def test_user_unique_email(db_session: AsyncSession):
"""测试邮箱唯一约束"""
# 创建用户组
group = Group(name="默认组")
group = await group.save(db_session)
# 创建第一个用户
user1 = User(
username="duplicate",
email="duplicate@test.local",
password="password1",
group_id=group.id
)
@@ -50,7 +50,7 @@ async def test_user_unique_username(db_session: AsyncSession):
# 尝试创建同名用户
user2 = User(
username="duplicate",
email="duplicate@test.local",
password="password2",
group_id=group.id
)
@@ -68,7 +68,7 @@ async def test_user_to_public(db_session: AsyncSession):
# 创建用户
user = User(
username="publicuser",
email="publicuser@test.local",
nickname="公开用户",
password="secret_password",
storage=1024,
@@ -82,7 +82,7 @@ async def test_user_to_public(db_session: AsyncSession):
assert isinstance(public_user, UserPublic)
assert public_user.id == user.id
assert public_user.username == "publicuser"
assert public_user.email == "publicuser@test.local"
# 注意: UserPublic.nick 字段名与 User.nickname 不同,
# model_validate 不会自动映射,所以 nick 为 None
# 这是已知的设计问题,需要在 UserPublic 中添加别名或重命名字段
@@ -101,7 +101,7 @@ async def test_user_group_relationship(db_session: AsyncSession):
# 创建用户
user = User(
username="vipuser",
email="vipuser@test.local",
password="password",
group_id=group.id
)
@@ -125,7 +125,7 @@ async def test_user_status_default(db_session: AsyncSession):
group = await group.save(db_session)
user = User(
username="defaultuser",
email="defaultuser@test.local",
password="password",
group_id=group.id
)
@@ -141,7 +141,7 @@ async def test_user_storage_default(db_session: AsyncSession):
group = await group.save(db_session)
user = User(
username="storageuser",
email="storageuser@test.local",
password="password",
group_id=group.id
)
@@ -158,7 +158,7 @@ async def test_user_theme_enum(db_session: AsyncSession):
# 测试默认值
user1 = User(
username="user1",
email="user1@test.local",
password="password",
group_id=group.id
)
@@ -167,7 +167,7 @@ async def test_user_theme_enum(db_session: AsyncSession):
# 测试设置为 LIGHT
user2 = User(
username="user2",
email="user2@test.local",
password="password",
theme=ThemeType.LIGHT,
group_id=group.id
@@ -177,7 +177,7 @@ async def test_user_theme_enum(db_session: AsyncSession):
# 测试设置为 DARK
user3 = User(
username="user3",
email="user3@test.local",
password="password",
theme=ThemeType.DARK,
group_id=group.id