From 6b0d163ac08e40d5c9b1a575cba6337156a521ae Mon Sep 17 00:00:00 2001 From: lou Date: Mon, 10 Aug 2026 15:31:04 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AD=98=E5=82=A8=E6=8C=89=E7=94=A8=E6=88=B7?= =?UTF-8?q?=E5=88=86=E7=9B=AE=E5=BD=95:=20storage/=E7=94=A8=E6=88=B7?= =?UTF-8?q?=E5=90=8D/=E6=97=A5=E6=9C=9F/=E4=BB=BB=E5=8A=A1ID=20(=E7=89=A9?= =?UTF-8?q?=E7=90=86=E9=9A=94=E7=A6=BB,=20=E6=97=A7=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=E5=85=BC=E5=AE=B9);=20=E6=B5=8B=E8=AF=95=E6=96=AD=E8=A8=80=20a?= =?UTF-8?q?dmin=20=E7=9B=AE=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 6 ++++-- api.py | 2 +- storage.py | 8 +++++--- tests/test_api.py | 2 ++ 4 files changed, 12 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index c5e25e3..af71afa 100644 --- a/README.md +++ b/README.md @@ -73,8 +73,10 @@ tail -f /tmp/sz-server.log # 实时看 ``` data/ - ├─ app.db SQLite (transfers / files / chunks) - ├─ storage/日期/任务ID/ 密文卷目录 (chunk_0001..N, 不合并) + ├─ app.db SQLite (users / transfers / files / chunks) + ├─ storage/用户名/日期/任务ID/ 密文卷目录 (每用户独立目录, chunk_0001..N, 不合并) + │ admin/ SZ_TOKEN 上传的文件 + │ 用户名/ 注册用户上传的文件 └─ tmp/任务ID/ 上传中的卷 (complete 后 move 入 storage) ``` diff --git a/api.py b/api.py index 043cd0d..55d51cd 100644 --- a/api.py +++ b/api.py @@ -250,7 +250,7 @@ async def complete(transfer_id: str, request: Request, username: str = Depends(v "error": f"缺卷: {transfer['chunk_count'] - len(got)} 卷未上传", }) tasks.set_status(transfer_id, "storing") - final_dir = storage.store_chunks(transfer_id, TMP_ROOT / transfer_id) + final_dir = storage.store_chunks(transfer_id, TMP_ROOT / transfer_id, username) file_id = db.insert_file( transfer_id, transfer["file_name"], diff --git a/storage.py b/storage.py index 1016237..02d0320 100644 --- a/storage.py +++ b/storage.py @@ -20,12 +20,14 @@ class Storage: self.tasks = tasks self.storage_root = Path(storage_root) - def store_chunks(self, transfer_id: str, chunk_dir: Path) -> Path: - """卷目录 -> 最终存储目录 (整体 move, 返回目标目录路径) + def store_chunks(self, transfer_id: str, chunk_dir: Path, user_id: str) -> Path: + """卷目录 -> 用户目录/日期/transfer_id (整体 move, 返回目标目录路径) + 每用户独立目录 (user_id 已过注册校验: 3-32 位字母数字/下划线, 无路径风险)。 注意: 目标目录不能预创建, 否则 shutil.move 会嵌套成 dst/dst/。 """ - day_dir = self.storage_root / datetime.now().strftime("%Y-%m-%d") + user_dir = self.storage_root / user_id + day_dir = user_dir / datetime.now().strftime("%Y-%m-%d") final_dir = day_dir / transfer_id if final_dir.exists(): raise OSError(f"存储目录已存在: {final_dir}") diff --git a/tests/test_api.py b/tests/test_api.py index 4ff9a8d..860b241 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -117,6 +117,8 @@ class ServerPipelineTest(unittest.TestCase): self.assertIsNotNone(row) chunk_dir = Path(row["path"]) self.assertTrue(chunk_dir.is_dir()) + # 每用户独立目录: admin 上传 -> storage/admin/日期/transfer_id + self.assertIn("admin", chunk_dir.parts) chunk_files_on_disk = sorted(chunk_dir.glob("chunk_*")) self.assertEqual(len(chunk_files_on_disk), len(chunk_files)) # 卷内容与客户端上传的卷一致