feat: add Docker support and update backend dependencies

- Introduced `requirements.docker.txt` for Docker-specific dependencies.
- Updated `requirements.txt` to include `psycopg[binary]` and `python-multipart`.
- Enhanced test suite in `test_main_endpoints.py` to cover document CRUD operations.
- Modified `docker-compose.yml` to include PostgreSQL and frontend services.
- Added Nginx configuration for reverse proxying API requests.
- Refactored file handling in Vue components to support new document storage backend.
- Created new utility functions in `docsApi.js` for document management.
- Updated configuration to support new API endpoints for document operations.
- Adjusted Vite configuration to proxy API requests to the local backend.
This commit is contained in:
“ydy0615”
2026-06-06 17:18:15 +08:00
parent 81f711ef0b
commit b55af1eff0
20 changed files with 1413 additions and 407 deletions
+69
View File
@@ -7,6 +7,7 @@ from pathlib import Path
from fastapi.testclient import TestClient
os.environ["JOB_BACKEND"] = "memory"
os.environ["DOCS_BACKEND"] = "memory"
CURRENT_DIR = Path(__file__).resolve().parent
BACKEND_DIR = CURRENT_DIR.parent
@@ -15,6 +16,7 @@ if str(BACKEND_DIR) not in sys.path:
import job_handlers # type: ignore
import job_system # type: ignore
import docs_store # type: ignore
main = importlib.import_module("main")
@@ -23,6 +25,7 @@ HEADERS = {"X-API-Key": main.API_KEY}
def setup_function():
job_system.reset_job_manager()
docs_store.reset_document_store()
main._handlers_registered = False
@@ -119,3 +122,69 @@ def test_post_convert_unsupported_extension_returns_500():
})
assert resp.status_code == 500
assert "仅支持" in resp.json()["error"]
def test_docs_nodes_crud_round_trip():
with TestClient(main.app) as client:
folder_resp = client.post("/v1/docs/folders", headers=HEADERS, json={
"name": "项目资料",
"parentId": None,
})
assert folder_resp.status_code == 200
folder = folder_resp.json()["node"]
file_resp = client.post("/v1/docs/files/text", headers=HEADERS, json={
"name": "notes.md",
"parentId": folder["id"],
"content": "# hello",
})
assert file_resp.status_code == 200
file_node = file_resp.json()["node"]
assert file_node["previewText"] == "# hello"
list_resp = client.get("/v1/docs/nodes", headers=HEADERS)
assert list_resp.status_code == 200
nodes = list_resp.json()["nodes"]
assert len(nodes) == 2
rename_resp = client.patch(f"/v1/docs/nodes/{file_node['id']}", headers=HEADERS, json={
"name": "renamed.md",
})
assert rename_resp.status_code == 200
assert rename_resp.json()["node"]["name"] == "renamed.md"
blob_resp = client.get(f"/v1/docs/files/{file_node['id']}/blob", headers=HEADERS)
assert blob_resp.status_code == 200
assert blob_resp.content == b"# hello"
delete_resp = client.delete(f"/v1/docs/nodes/{folder['id']}", headers=HEADERS)
assert delete_resp.status_code == 200
final_list = client.get("/v1/docs/nodes", headers=HEADERS)
assert final_list.status_code == 200
assert final_list.json()["nodes"] == []
def test_docs_file_upload_and_blob_replace():
with TestClient(main.app) as client:
upload_resp = client.post(
"/v1/docs/files/upload",
headers=HEADERS,
files={"file": ("image.png", b"png-bytes", "image/png")},
data={"parent_id": ""},
)
assert upload_resp.status_code == 200
node = upload_resp.json()["node"]
assert node["storageKind"] == "blob"
replace_resp = client.put(
f"/v1/docs/files/{node['id']}/blob",
headers=HEADERS,
files={"file": ("photo.jpg", b"jpeg-bytes", "image/jpeg")},
)
assert replace_resp.status_code == 200
assert replace_resp.json()["node"]["name"] == "photo.jpg"
blob_resp = client.get(f"/v1/docs/files/{node['id']}/blob", headers=HEADERS)
assert blob_resp.status_code == 200
assert blob_resp.content == b"jpeg-bytes"