| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115 |
- """Public attachment upload (local storage)."""
- import pytest
- from app.core.config import get_settings
- PNG = b"\x89PNG\r\n\x1a\n" + b"\x00" * 8
- PDF = b"%PDF-1.4" + b"\x00" * 16
- @pytest.fixture
- def local_storage_env(tmp_path, monkeypatch):
- monkeypatch.setenv("STORAGE_TYPE", "local")
- monkeypatch.setenv("LOCAL_STORAGE_DIR", str(tmp_path))
- get_settings.cache_clear()
- yield tmp_path
- get_settings.cache_clear()
- def test_public_upload(client, local_storage_env):
- files = {"file": ("a.png", PNG, "image/png")}
- r = client.post(
- "/api/public/attachment/upload",
- files=files,
- data={"folder": "feedback"},
- )
- assert r.status_code == 200
- data = r.json()["data"]
- assert data["url"]
- assert data["id"]
- assert data["fileName"] == "a.png"
- assert data["size"] == len(PNG)
- assert data["url"].startswith("/uploads/feedback/")
- def test_public_upload_pdf(client, local_storage_env):
- files = {"file": ("report.pdf", PDF, "application/pdf")}
- r = client.post(
- "/api/public/attachment/upload",
- files=files,
- data={"folder": "suggestion"},
- )
- assert r.status_code == 200
- data = r.json()["data"]
- assert data["fileName"] == "report.pdf"
- assert data["url"].endswith(".pdf") or ".pdf" in data["url"]
- def test_public_upload_rejects_disallowed_extension(client, local_storage_env):
- files = {"file": ("malware.exe", b"MZ", "application/octet-stream")}
- r = client.post(
- "/api/public/attachment/upload",
- files=files,
- data={"folder": "feedback"},
- )
- assert r.status_code == 400
- body = r.json()
- assert body["code"] == 400
- assert "类型" in body["message"] or "格式" in body["message"] or "不支持" in body["message"]
- def test_public_upload_allows_large_file(client, local_storage_env):
- # 原 20MB 限制已取消;略超原阈值仍应成功
- big = b"%PDF-1.4" + b"x" * (20 * 1024 * 1024)
- files = {"file": ("big.pdf", big, "application/pdf")}
- r = client.post(
- "/api/public/attachment/upload",
- files=files,
- data={"folder": "feedback"},
- )
- assert r.status_code == 200
- data = r.json()["data"]
- assert data["fileName"] == "big.pdf"
- assert data["size"] == len(big)
- def test_public_upload_rejects_path_traversal(client, local_storage_env):
- base = local_storage_env
- outside = (base / ".." / "outside").resolve()
- assert not outside.exists()
- files = {"file": ("evil.png", PNG, "image/png")}
- r = client.post(
- "/api/public/attachment/upload",
- files=files,
- data={"folder": "../outside"},
- )
- assert r.status_code == 400
- body = r.json()
- assert body["code"] == 400
- assert "message" in body
- assert "detail" not in body
- assert not outside.exists()
- assert not any(base.rglob("*"))
- def test_public_upload_rejects_qrcode_folder(client, local_storage_env):
- files = {"file": ("a.png", PNG, "image/png")}
- r = client.post(
- "/api/public/attachment/upload",
- files=files,
- data={"folder": "qrcode"},
- )
- assert r.status_code == 400
- assert r.json()["code"] == 400
- def test_public_upload_allows_feedback_folder(client, local_storage_env):
- files = {"file": ("a.png", PNG, "image/png")}
- r = client.post(
- "/api/public/attachment/upload",
- files=files,
- data={"folder": "feedback"},
- )
- assert r.status_code == 200
- assert "/feedback/" in r.json()["data"]["url"]
|