224 lines
7.9 KiB
Python
224 lines
7.9 KiB
Python
"""继续教育:在线教育外链卡片与教育公告。工作人员写入,门户公开读取。"""
|
|
|
|
import pytest
|
|
from fastapi.testclient import TestClient
|
|
|
|
from app.core.config import get_settings
|
|
from app.core.security import create_access_token
|
|
|
|
|
|
@pytest.fixture
|
|
def client(monkeypatch):
|
|
monkeypatch.setenv("JWT_SECRET", "test-secret-must-be-32-characters!")
|
|
monkeypatch.setenv("API_PAYLOAD_ENCRYPT", "false")
|
|
get_settings.cache_clear()
|
|
if not get_settings().database_url.strip():
|
|
pytest.skip("DATABASE_URL 为空")
|
|
from app.main import create_app
|
|
|
|
with TestClient(create_app()) as api:
|
|
yield api
|
|
get_settings.cache_clear()
|
|
|
|
|
|
def _headers(token_type: str) -> dict[str, str]:
|
|
return {"Authorization": f"Bearer {create_access_token('1', token_type)}"}
|
|
|
|
|
|
def _minio_ready() -> bool:
|
|
try:
|
|
from app.services.storage import ensure_buckets
|
|
|
|
ensure_buckets()
|
|
return True
|
|
except Exception:
|
|
return False
|
|
|
|
|
|
def _png() -> bytes:
|
|
return (
|
|
b"\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x01\x00\x00\x00\x01"
|
|
b"\x08\x02\x00\x00\x00\x90wS\xde\x00\x00\x00\x0cIDATx\x9cc\xf8\x0f"
|
|
b"\x00\x00\x01\x01\x00\x05\x18\xd8N\x00\x00\x00\x00IEND\xaeB`\x82"
|
|
)
|
|
|
|
|
|
def _clear_notices(client, staff: dict[str, str]) -> None:
|
|
listed = client.get("/api/admin/about/articles/edu_notices", headers=staff)
|
|
assert listed.status_code == 200, listed.text
|
|
for item in listed.json().get("items") or []:
|
|
deleted = client.delete(f"/api/admin/home/articles/{item['id']}", headers=staff)
|
|
assert deleted.status_code in (200, 204), deleted.text
|
|
|
|
|
|
def test_edu_platforms_are_public_cards_and_notices_follow_publish_rules(client):
|
|
if not _minio_ready():
|
|
pytest.skip("MinIO 不可达")
|
|
staff = _headers("staff")
|
|
file_ids: list[int] = []
|
|
try:
|
|
empty = client.get("/api/site/edu/platforms")
|
|
assert empty.status_code == 200, empty.text
|
|
assert empty.json()["placeholder"] == "暂无在线教育"
|
|
|
|
missing = client.put(
|
|
"/api/admin/edu/platforms",
|
|
headers=staff,
|
|
json={"items": [{"name": "省继续教育", "url": "https://example.com/edu", "sortOrder": 1}]},
|
|
)
|
|
assert missing.status_code == 400
|
|
assert "图片" in missing.text
|
|
|
|
script_url = client.put(
|
|
"/api/admin/edu/platforms",
|
|
headers=staff,
|
|
json={
|
|
"items": [
|
|
{
|
|
"name": "省继续教育",
|
|
"url": "javascript:alert(1)",
|
|
"imageFileId": 1,
|
|
"sortOrder": 1,
|
|
}
|
|
]
|
|
},
|
|
)
|
|
assert script_url.status_code == 400
|
|
|
|
cover = client.post(
|
|
"/api/admin/files",
|
|
headers=staff,
|
|
data={"bucket": "public"},
|
|
files={"file": ("platform.png", _png(), "image/png")},
|
|
)
|
|
assert cover.status_code == 200, cover.text
|
|
file_ids.append(cover.json()["id"])
|
|
second = client.post(
|
|
"/api/admin/files",
|
|
headers=staff,
|
|
data={"bucket": "public"},
|
|
files={"file": ("later.png", _png(), "image/png")},
|
|
)
|
|
assert second.status_code == 200, second.text
|
|
file_ids.append(second.json()["id"])
|
|
|
|
saved = client.put(
|
|
"/api/admin/edu/platforms",
|
|
headers=staff,
|
|
json={
|
|
"items": [
|
|
{
|
|
"name": "后配置的平台",
|
|
"url": "https://example.com/later",
|
|
"imageFileId": file_ids[1],
|
|
"sortOrder": 2,
|
|
},
|
|
{
|
|
"name": "甘肃省继续教育",
|
|
"url": "https://example.com/edu",
|
|
"imageFileId": file_ids[0],
|
|
"sortOrder": 1,
|
|
},
|
|
]
|
|
},
|
|
)
|
|
assert saved.status_code == 200, saved.text
|
|
|
|
admin_list = client.get("/api/admin/edu/platforms", headers=staff)
|
|
assert admin_list.status_code == 200, admin_list.text
|
|
assert [item["name"] for item in admin_list.json()["items"]] == [
|
|
"甘肃省继续教育",
|
|
"后配置的平台",
|
|
]
|
|
|
|
public = client.get("/api/site/edu/platforms")
|
|
assert public.status_code == 200, public.text
|
|
body = public.json()
|
|
assert "placeholder" not in body
|
|
assert [item["name"] for item in body["items"]] == ["甘肃省继续教育", "后配置的平台"]
|
|
first = body["items"][0]
|
|
assert first["url"] == "https://example.com/edu"
|
|
assert first["navigation"] == "newWindow"
|
|
assert first["imageUrl"]
|
|
assert "imageFileId" not in first
|
|
|
|
rejected = client.put(
|
|
"/api/admin/edu/platforms",
|
|
headers=_headers("member"),
|
|
json={"items": []},
|
|
)
|
|
assert rejected.status_code in (401, 403)
|
|
assert client.get("/api/site/edu/platforms").json()["items"][0]["name"] == "甘肃省继续教育"
|
|
|
|
shortcut = client.put(
|
|
"/api/admin/home/menu",
|
|
headers=staff,
|
|
json={
|
|
"items": [
|
|
{
|
|
"key": "edu",
|
|
"label": "继续教育",
|
|
"url": "https://example.com/edu",
|
|
"visible": True,
|
|
"sortOrder": 1,
|
|
}
|
|
]
|
|
},
|
|
)
|
|
assert shortcut.status_code == 400
|
|
labels = [item["label"] for item in client.get("/api/site/home").json()["shortcutMenu"]["items"]]
|
|
assert "继续教育" not in labels
|
|
|
|
_clear_notices(client, staff)
|
|
empty_notices = client.get("/api/site/about/articles/edu_notices")
|
|
assert empty_notices.status_code == 200, empty_notices.text
|
|
assert empty_notices.json()["placeholder"] == "暂无教育公告"
|
|
|
|
draft = client.post(
|
|
"/api/admin/home/articles",
|
|
headers=staff,
|
|
json={
|
|
"category": "edu_notices",
|
|
"title": "内部培训草稿",
|
|
"published": False,
|
|
"bodyHtml": "<p>尚未公示</p>",
|
|
"attachmentFileIds": [],
|
|
},
|
|
)
|
|
assert draft.status_code == 200, draft.text
|
|
published = client.post(
|
|
"/api/admin/home/articles",
|
|
headers=staff,
|
|
json={
|
|
"category": "edu_notices",
|
|
"title": "2026年度培训计划",
|
|
"published": True,
|
|
"bodyHtml": "<p>线上与线下安排</p><script>alert(1)</script>",
|
|
"imageFileId": file_ids[0],
|
|
"attachmentFileIds": [],
|
|
},
|
|
)
|
|
assert published.status_code == 200, published.text
|
|
|
|
notices = client.get("/api/site/about/articles/edu_notices")
|
|
assert notices.status_code == 200, notices.text
|
|
titles = [item["title"] for item in notices.json()["items"]]
|
|
assert titles == ["2026年度培训计划"]
|
|
assert "内部培训草稿" not in notices.text
|
|
assert notices.json()["items"][0]["imageUrl"]
|
|
|
|
detail = client.get(f"/api/site/home/articles/{published.json()['id']}")
|
|
assert detail.status_code == 200, detail.text
|
|
assert "线上与线下安排" in detail.text
|
|
assert "script" not in detail.text
|
|
assert "alert" not in detail.text
|
|
|
|
home = client.get("/api/admin/home", headers=staff)
|
|
categories = {item["category"] for item in home.json()["articles"]}
|
|
assert "edu_notices" not in categories
|
|
finally:
|
|
client.put("/api/admin/edu/platforms", headers=staff, json={"items": []})
|
|
_clear_notices(client, staff)
|
|
for file_id in file_ids:
|
|
client.delete(f"/api/admin/files/{file_id}", headers=staff)
|