回收站,软删除(三天自动清空),以及默认链接三十分钟失效
This commit is contained in:
@@ -23,14 +23,14 @@ def _setup_kb(client: TestClient) -> tuple[str, str]:
|
||||
return kb_id, resp.json()["token"]
|
||||
|
||||
|
||||
def test_default_permanent() -> None:
|
||||
def test_default_30min() -> None:
|
||||
"""新建知识库链接默认 30 分钟有效期。"""
|
||||
with _client() as client:
|
||||
kb_id, token = _setup_kb(client)
|
||||
resp = client.get(f"/k/{token}")
|
||||
assert resp.status_code == 200
|
||||
# link 接口返回长期有效
|
||||
resp = client.get(f"/api/knowledge-bases/{kb_id}/link")
|
||||
assert resp.json()["expires_at"] is None
|
||||
assert resp.json()["expires_at"] is not None
|
||||
assert resp.json()["is_expired"] is False
|
||||
|
||||
|
||||
@@ -106,13 +106,14 @@ def test_regenerate_resets_expiry() -> None:
|
||||
kb_id, old_token = _setup_kb(client)
|
||||
client.post(f"/api/knowledge-bases/{kb_id}/set-expiry",
|
||||
json={"expires_in_minutes": -1})
|
||||
# 重新生成 → 新链接长期有效
|
||||
# 重新生成 → 新链接默认 30 分钟有效期
|
||||
resp = client.post(f"/api/knowledge-bases/{kb_id}/regenerate-token")
|
||||
new_token = resp.json()["token"]
|
||||
assert new_token != old_token
|
||||
assert client.get(f"/k/{new_token}").status_code == 200
|
||||
resp = client.get(f"/api/knowledge-bases/{kb_id}/link")
|
||||
assert resp.json()["expires_at"] is None
|
||||
assert resp.json()["expires_at"] is not None
|
||||
assert resp.json()["is_expired"] is False
|
||||
|
||||
|
||||
def _make_docx_bytes() -> bytes:
|
||||
@@ -124,8 +125,8 @@ def _make_docx_bytes() -> bytes:
|
||||
return buf.getvalue()
|
||||
|
||||
|
||||
def test_doc_delete_removes_files() -> None:
|
||||
"""删除文档后物理文件应被清理。"""
|
||||
def test_doc_delete_goes_to_recycle_bin() -> None:
|
||||
"""删除文档 → 进回收站,文件保留;彻底删除后文件清理。"""
|
||||
with _client() as client:
|
||||
client.post("/api/auth/register", json={
|
||||
"username": "cleanup_user", "email": "cleanup@example.com", "password": "password123",
|
||||
@@ -138,31 +139,37 @@ def test_doc_delete_removes_files() -> None:
|
||||
client.post("/api/documents/upload", data={"kb_id": kb_id}, files=files)
|
||||
|
||||
resp = client.get(f"/api/documents?kb_id={kb_id}")
|
||||
doc = resp.json()["items"][0]
|
||||
storage_path = doc["storage_path"] if "storage_path" in doc else None
|
||||
doc_id = doc["id"]
|
||||
doc_id = resp.json()["items"][0]["id"]
|
||||
|
||||
# 删除文档
|
||||
resp = client.delete(f"/api/documents/{doc_id}")
|
||||
assert resp.status_code == 204
|
||||
|
||||
# 验证物理文件已删除
|
||||
from app.core.config import get_settings
|
||||
from pathlib import Path
|
||||
# 通过数据库查询 storage_path(响应里没有)
|
||||
|
||||
from app.core.config import get_settings
|
||||
from app.core.db import get_session_factory
|
||||
from app.models.document import Document
|
||||
|
||||
factory = get_session_factory()
|
||||
with factory() as session:
|
||||
d = session.get(Document, doc_id)
|
||||
storage_path = d.storage_path
|
||||
if storage_path:
|
||||
full = Path(get_settings().storage_root_path) / storage_path
|
||||
assert not full.exists(), f"文件未被清理: {full}"
|
||||
|
||||
# 删除 → 进回收站,文件仍存在
|
||||
resp = client.delete(f"/api/documents/{doc_id}")
|
||||
assert resp.status_code == 204
|
||||
full = Path(get_settings().storage_root_path) / storage_path
|
||||
assert full.exists(), "回收站阶段文件不应被删除"
|
||||
|
||||
# 回收站列表可见
|
||||
resp = client.get("/api/recycle-bin")
|
||||
assert any(item["id"] == doc_id for item in resp.json()["documents"])
|
||||
|
||||
# 彻底删除 → 文件清理
|
||||
resp = client.delete(f"/api/recycle-bin/documents/{doc_id}")
|
||||
assert resp.status_code == 204
|
||||
assert not full.exists(), "彻底删除后文件应被清理"
|
||||
|
||||
|
||||
def test_kb_delete_removes_doc_files() -> None:
|
||||
"""删除知识库后其下所有文档文件应被清理。"""
|
||||
def test_kb_delete_goes_to_recycle_bin() -> None:
|
||||
"""删除知识库 → 进回收站;彻底删除后文件清理。"""
|
||||
with _client() as client:
|
||||
client.post("/api/auth/register", json={
|
||||
"username": "kb_cleanup_user", "email": "kbcleanup@example.com", "password": "password123",
|
||||
@@ -174,20 +181,71 @@ def test_kb_delete_removes_doc_files() -> None:
|
||||
"application/vnd.openxmlformats-officedocument.wordprocessingml.document")}
|
||||
client.post("/api/documents/upload", data={"kb_id": kb_id}, files=files)
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
from app.core.config import get_settings
|
||||
from app.core.db import get_session_factory
|
||||
from app.models.document import Document
|
||||
from app.core.config import get_settings
|
||||
from pathlib import Path
|
||||
|
||||
factory = get_session_factory()
|
||||
with factory() as session:
|
||||
docs = list(session.query(Document).filter_by(knowledge_base_id=kb_id).all())
|
||||
paths = [d.storage_path for d in docs if d.storage_path]
|
||||
|
||||
# 删除知识库
|
||||
# 删除知识库 → 回收站,文件保留
|
||||
resp = client.delete(f"/api/knowledge-bases/{kb_id}")
|
||||
assert resp.status_code == 204
|
||||
|
||||
root = Path(get_settings().storage_root_path)
|
||||
for p in paths:
|
||||
assert not (root / p).exists(), f"文件未被清理: {p}"
|
||||
assert (root / p).exists(), "回收站阶段文件不应被删除"
|
||||
|
||||
# 回收站可见
|
||||
resp = client.get("/api/recycle-bin")
|
||||
assert any(item["id"] == kb_id for item in resp.json()["knowledge_bases"])
|
||||
|
||||
# 彻底删除 → 文件清理
|
||||
resp = client.delete(f"/api/recycle-bin/knowledge-bases/{kb_id}")
|
||||
assert resp.status_code == 204
|
||||
for p in paths:
|
||||
assert not (root / p).exists(), "彻底删除后文件应被清理"
|
||||
|
||||
|
||||
def test_category_delete_and_restore() -> None:
|
||||
"""删除目录 → 目录+子目录+文档进回收站;恢复后全部回来。"""
|
||||
with _client() as client:
|
||||
client.post("/api/auth/register", json={
|
||||
"username": "cat_rb_user", "email": "catrb@example.com", "password": "password123",
|
||||
})
|
||||
resp = client.post("/api/knowledge-bases", json={"name": "Cat RB KB"})
|
||||
kb_id = resp.json()["id"]
|
||||
|
||||
# 在"01 公司层"下创建文本文档
|
||||
cats = client.get(f"/api/knowledge-bases/{kb_id}/categories").json()
|
||||
target = next(c for c in cats if c["name"] == "公司基本信息")
|
||||
|
||||
client.post("/api/documents/create-text", json={
|
||||
"kb_id": kb_id, "title": "Cat Doc", "content": "hello",
|
||||
"category_id": target["id"],
|
||||
})
|
||||
|
||||
# 删除目录
|
||||
resp = client.delete(f"/api/knowledge-bases/{kb_id}/categories/{target['id']}")
|
||||
assert resp.status_code == 204
|
||||
|
||||
# 文档不可见
|
||||
docs = client.get(f"/api/documents?kb_id={kb_id}").json()
|
||||
assert docs["total"] == 0
|
||||
|
||||
# 回收站里有目录和文档
|
||||
rb = client.get("/api/recycle-bin").json()
|
||||
assert any(c["name"] == "公司基本信息" for c in rb["categories"])
|
||||
assert any(d["name"] == "Cat Doc" for d in rb["documents"])
|
||||
|
||||
# 恢复目录 → 同批文档恢复
|
||||
cat_id = next(c["id"] for c in rb["categories"] if c["name"] == "公司基本信息")
|
||||
resp = client.post(f"/api/recycle-bin/categories/{cat_id}/restore")
|
||||
assert resp.status_code == 204
|
||||
|
||||
docs = client.get(f"/api/documents?kb_id={kb_id}").json()
|
||||
assert docs["total"] == 1
|
||||
assert docs["items"][0]["title"] == "Cat Doc"
|
||||
Reference in New Issue
Block a user