"""栏目文章三类:工作人员写入 → 门户公开读取。""" 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 _clear_column_category(client, staff: dict[str, str], category: str) -> None: listed = client.get(f"/api/admin/about/articles/{category}", 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_column_articles_publish_filter_and_placeholders(client): if not _minio_ready(): pytest.skip("MinIO 不可达") staff = _headers("staff") article_ids: list[int] = [] file_ids: list[int] = [] try: for category in ("work_briefs", "annual_reports", "qualifications"): _clear_column_category(client, staff, category) empty_briefs = client.get("/api/site/about/articles/work_briefs") assert empty_briefs.status_code == 200, empty_briefs.text assert "暂无工作简报" in empty_briefs.text assert "暂无年度报告或工作计划" in client.get("/api/site/about/articles/annual_reports").text assert "暂无资质与荣誉" in client.get("/api/site/about/articles/qualifications").text pdf = client.post( "/api/admin/files", headers=staff, data={"bucket": "public"}, files={"file": ("批复扫描件.pdf", b"%PDF-1.4\nscan", "application/pdf")}, ) assert pdf.status_code == 200, pdf.text file_ids.append(pdf.json()["id"]) report = client.post( "/api/admin/home/articles", headers=staff, json={ "category": "annual_reports", "title": "2025年协会工作报告", "publishedAt": "2026-01-15T08:00:00", "published": True, "bodyHtml": "

公开公示版

", "attachmentFileIds": [], }, ) assert report.status_code == 200, report.text article_ids.append(report.json()["id"]) draft = client.post( "/api/admin/home/articles", headers=staff, json={ "category": "annual_reports", "title": "内部财务稿", "publishedAt": "2026-01-16T08:00:00", "published": False, "bodyHtml": "

内部财务稿

", "attachmentFileIds": [], }, ) assert draft.status_code == 200, draft.text article_ids.append(draft.json()["id"]) honor = client.post( "/api/admin/home/articles", headers=staff, json={ "category": "qualifications", "title": "主管单位批复文件", "publishedAt": "2024-03-01T08:00:00", "published": True, "bodyHtml": "

批复摘要

", "attachmentFileIds": [file_ids[0]], }, ) assert honor.status_code == 200, honor.text article_ids.append(honor.json()["id"]) reports = client.get("/api/site/about/articles/annual_reports") assert reports.status_code == 200, reports.text assert "2025年协会工作报告" in reports.text assert "内部财务稿" not in reports.text assert "暂无年度报告或工作计划" not in reports.text detail = client.get(f"/api/site/home/articles/{article_ids[0]}") assert detail.status_code == 200, detail.text body = detail.json()["bodyHtml"].lower() assert "公开公示版" in detail.json()["bodyHtml"] assert "script" not in body assert "alert" not in body hidden = client.get(f"/api/site/home/articles/{article_ids[1]}") assert hidden.status_code == 404 honors = client.get("/api/site/about/articles/qualifications") assert honors.status_code == 200, honors.text assert "主管单位批复文件" in honors.text honor_detail = client.get(f"/api/site/home/articles/{article_ids[2]}") assert honor_detail.status_code == 200, honor_detail.text assert [item["filename"] for item in honor_detail.json()["attachments"]] == ["批复扫描件.pdf"] home = client.get("/api/site/home") assert home.status_code == 200, home.text home_json = home.json() assert "annual_reports" not in home_json assert "work_briefs" not in home_json assert "qualifications" not in home_json assert "2025年协会工作报告" not in home.text editor = client.get("/api/admin/home", headers=staff) assert editor.status_code == 200, editor.text categories = {item["category"] for item in editor.json()["articles"]} assert "annual_reports" not in categories assert "work_briefs" not in categories assert "qualifications" not in categories rejected = client.post( "/api/admin/home/articles", headers=_headers("member"), json={ "category": "work_briefs", "title": "会员不得发布", "published": True, "bodyHtml": "

x

", "attachmentFileIds": [], }, ) assert rejected.status_code in (401, 403) assert "会员不得发布" not in client.get("/api/site/about/articles/work_briefs").text assert "暂无工作简报" in client.get("/api/site/about/articles/work_briefs").text finally: for article_id in article_ids: client.delete(f"/api/admin/home/articles/{article_id}", headers=staff) for file_id in file_ids: client.delete(f"/api/admin/files/{file_id}", headers=staff) def test_column_articles_public_pagination(client): if not _minio_ready(): pytest.skip("MinIO 不可达") staff = _headers("staff") article_ids: list[int] = [] try: _clear_column_category(client, staff, "work_briefs") for index in range(11): created = client.post( "/api/admin/home/articles", headers=staff, json={ "category": "work_briefs", "title": f"简报分页样例-{index:02d}", "publishedAt": f"2026-02-{index + 1:02d}T08:00:00", "published": True, "bodyHtml": f"

简报分页样例-{index:02d}

", "attachmentFileIds": [], }, ) assert created.status_code == 200, created.text article_ids.append(created.json()["id"]) page1 = client.get("/api/site/about/articles/work_briefs?current=1&size=10") assert page1.status_code == 200, page1.text body1 = page1.json() assert body1["total"] == 11 assert body1["current"] == 1 assert body1["size"] == 10 assert len(body1["items"]) == 10 assert body1["items"][0]["title"] == "简报分页样例-10" page2 = client.get("/api/site/about/articles/work_briefs?current=2&size=10") assert page2.status_code == 200, page2.text body2 = page2.json() assert body2["total"] == 11 assert body2["current"] == 2 assert len(body2["items"]) == 1 assert body2["items"][0]["title"] == "简报分页样例-00" size20 = client.get("/api/site/about/articles/work_briefs?current=1&size=20") assert size20.status_code == 200, size20.text assert size20.json()["size"] == 20 assert len(size20.json()["items"]) == 11 bad_size = client.get("/api/site/about/articles/work_briefs?current=1&size=15") assert bad_size.status_code == 200, bad_size.text assert bad_size.json()["size"] == 10 assert len(bad_size.json()["items"]) == 10 finally: for article_id in article_ids: client.delete(f"/api/admin/home/articles/{article_id}", headers=staff)