You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 

8.9 KiB

文件夹服务 Repository 层补全

日期:2026-02-04
类型:功能补全
影响范围:后端 - 文件夹服务


变更概述

补全文件夹服务的 Repository 层实现,新增分享和导出功能的数据访问层。


变更内容

1. 新增 FolderShareRepository

文件server/app/repositories/folder_share_repository.py

功能

  • 用户分享管理(创建、查询、撤销)
  • 链接分享管理(创建、查询、撤销、访问计数)
  • 分享列表查询(按文件夹、按用户)
  • 支持过期时间和密码保护

核心方法

- get_by_id(share_id) - 查询分享记录
- get_user_share_by_folder_and_user(folder_id, user_id) - 查询用户分享
- get_link_share_by_token(token) - 通过 token 查询链接分享
- create_user_share(folder_id, user_id, role, created_by) - 创建用户分享
- create_link_share(folder_id, token, access_level, ...) - 创建链接分享
- revoke_share(share_id) - 撤销分享
- increment_access_count(share_id) - 增加访问次数
- get_folder_shares(folder_id, share_type, include_revoked) - 获取文件夹分享列表
- get_user_shared_folders(user_id, page, page_size) - 获取用户被分享的文件夹
- count_user_shared_folders(user_id) - 统计用户被分享的文件夹数量

2. 新增 FolderExportRepository

文件server/app/repositories/folder_export_repository.py

功能

  • 导出任务管理(创建、查询、更新状态)
  • 导出结果设置(文件 URL、大小、过期时间)
  • 任务列表查询(按用户、按状态)
  • 过期任务清理

核心方法

- get_by_id(job_id) - 查询导出任务
- create(folder_id, user_id, format, ...) - 创建导出任务
- update_status(job_id, status, progress, error_message) - 更新导出状态
- set_result(job_id, file_url, file_size, expires_at) - 设置导出结果
- get_user_jobs(user_id, status, page, page_size) - 获取用户导出任务列表
- count_user_jobs(user_id, status) - 统计用户导出任务数量
- get_expired_jobs(limit) - 获取已过期的导出任务
- delete_job(job_id) - 删除导出任务
- cancel_job(job_id) - 取消导出任务

技术规范符合性

符合 jointo-tech-stack 规范

  1. 异步编程

    • 所有方法使用 async/await
    • 使用 AsyncSession 进行数据库操作
  2. 日志记录

    • 使用 app.core.logging.get_logger(__name__)
    • 关键操作记录日志(创建、更新、删除)
  3. 类型提示

    • 完整的类型注解(UUID、Optional、List)
    • 使用 SQLModel 类型
  4. 枚举类型

    • 使用 IntEnum(MemberRole、ExportStatus)
    • 数据库存储 SMALLINT
  5. 时间戳

    • 使用 datetime.now(timezone.utc) 生成 UTC 时间
    • 符合 ADR 006 规范(TIMESTAMPTZ)

数据库表关联

folder_shares 表

字段 类型 说明
id UUID 主键
folder_id UUID 文件夹 ID(逻辑外键)
share_type TEXT 分享类型(user/link)
shared_with_user_id UUID 被分享用户 ID
role SMALLINT 用户分享角色(1=owner, 2=editor, 3=viewer)
share_token TEXT 分享链接令牌
access_level SMALLINT 链接访问级别
password_hash TEXT 链接访问密码哈希
expires_at TIMESTAMPTZ 链接过期时间
access_count INTEGER 链接访问次数
created_by UUID 创建人 ID
created_at TIMESTAMPTZ 创建时间
revoked_at TIMESTAMPTZ 撤销时间

folder_export_jobs 表

字段 类型 说明
id UUID 主键
folder_id UUID 文件夹 ID(逻辑外键)
user_id UUID 用户 ID(逻辑外键)
format TEXT 导出格式(默认 zip)
include_subfolders BOOLEAN 是否包含子文件夹
include_resources BOOLEAN 是否包含资源文件
export_format TEXT 导出格式类型(native/json)
status SMALLINT 导出状态(1-5)
progress INTEGER 导出进度(0-100)
file_url TEXT 导出文件 URL
file_size BIGINT 文件大小(字节)
estimated_size BIGINT 预估文件大小
error_message TEXT 错误信息
created_at TIMESTAMPTZ 创建时间
started_at TIMESTAMPTZ 开始时间
completed_at TIMESTAMPTZ 完成时间
expires_at TIMESTAMPTZ 下载链接过期时间

已存在的相关迁移文件

  1. 初始化表结构20260127_1931_3a3a2a1417de_initial_schema_初始化所有表结构.py

    • 创建 folders 表
    • 创建 folder_members 表
  2. 触发器20260129_1400_add_folder_triggers.py

    • updated_at 自动更新触发器
    • 路径和层级自动计算触发器
    • folder_category 自动继承触发器
    • 唯一性索引(名称唯一性)
  3. 分享和导出表20260129_1410_create_folder_shares_and_export_jobs.py

    • 创建 folder_shares 表
    • 创建 folder_export_jobs 表
    • 添加索引和注释
  4. 时间戳修复20260129_1600_fix_folder_timestamp_timezone.py

    • 修改所有时间字段为 TIMESTAMPTZ
  5. 注释补充20260129_1700_add_folder_members_comments.md

    • 添加 folder_members 表注释

与现有代码的集成

FolderService 已集成

server/app/services/folder_service.py 中已经使用了这两个 Repository:

# 分享功能
async def share_folder_with_users(self, user_id, folder_id, users):
    from app.repositories.folder_share_repository import FolderShareRepository
    share_repo = FolderShareRepository(self.session)
    # ...

async def share_folder_with_link(self, user_id, folder_id, link_settings):
    from app.repositories.folder_share_repository import FolderShareRepository
    share_repo = FolderShareRepository(self.session)
    # ...

# 导出功能
async def create_export_job(self, user_id, folder_id, export_config):
    from app.repositories.folder_export_repository import FolderExportRepository
    export_repo = FolderExportRepository(self.session)
    # ...

async def get_export_job_status(self, user_id, job_id):
    from app.repositories.folder_export_repository import FolderExportRepository
    export_repo = FolderExportRepository(self.session)
    # ...

API 路由已集成

server/app/api/v1/folders.py 中已经定义了相关接口:

  • POST /api/v1/folders/{folder_id}/share - 分享文件夹
  • POST /api/v1/folders/{folder_id}/export - 创建导出任务
  • GET /api/v1/folders/export/{job_id} - 获取导出任务状态

测试建议

单元测试

# tests/unit/repositories/test_folder_share_repository.py
async def test_create_user_share()
async def test_create_link_share()
async def test_revoke_share()
async def test_get_folder_shares()

# tests/unit/repositories/test_folder_export_repository.py
async def test_create_export_job()
async def test_update_status()
async def test_set_result()
async def test_cancel_job()

集成测试

# tests/integration/test_folder_share.py
async def test_share_folder_with_user()
async def test_share_folder_with_link()
async def test_access_shared_folder()

# tests/integration/test_folder_export.py
async def test_export_folder()
async def test_export_job_lifecycle()
async def test_expired_job_cleanup()

后续工作

1. 后台任务处理

需要实现 Celery 任务处理导出:

# server/app/tasks/folder_export_tasks.py
@celery_app.task
async def process_folder_export(job_id: str):
    """处理文件夹导出任务"""
    # 1. 获取任务信息
    # 2. 收集文件夹内容
    # 3. 打包为 ZIP
    # 4. 上传到对象存储
    # 5. 更新任务状态

2. 过期任务清理

需要实现定时任务清理过期导出:

# server/app/tasks/folder_cleanup_tasks.py
@celery_app.task
async def cleanup_expired_exports():
    """清理过期的导出文件"""
    # 1. 查询过期任务
    # 2. 删除对象存储文件
    # 3. 删除数据库记录

3. 分享链接访问

需要实现公开访问接口:

# server/app/api/v1/public/shared_folders.py
@router.get("/shared/f/{token}")
async def access_shared_folder(token: str, password: Optional[str] = None):
    """访问分享链接"""
    # 1. 验证 token
    # 2. 检查过期时间
    # 3. 验证密码(如果有)
    # 4. 增加访问计数
    # 5. 返回文件夹内容

相关文档


总结

本次变更补全了文件夹服务的 Repository 层实现,新增了分享和导出功能的数据访问层。所有代码符合项目技术栈规范,与现有 Service 层和 API 层无缝集成。数据库迁移文件已存在,无需额外创建。