fix(site): 精简站点配置,移除名称/Banner/相关链接 (#15)
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
1 parent
608afb88ea
commit
460cfdc78a
8 files changed
+24
-238
No files matched your search
@@ -1,5 +1,3 @@
|
||||
import json
|
||||
|
||||
from fastapi import APIRouter, Depends, File, Form, HTTPException, Query, Request, UploadFile, status
|
||||
from pydantic import BaseModel
|
||||
from sqlalchemy import func, select
|
||||
@@ -28,7 +26,7 @@ from app.services.storage import (
|
||||
|
||||
router = APIRouter(dependencies=[Depends(require_staff)])
|
||||
|
||||
_TEXT_KEYS = {"site_name", "icp_text", "police_text", "link_cirea", "link_housing"}
|
||||
_TEXT_KEYS = {"icp_text", "police_text", "link_cirea", "link_housing"}
|
||||
_LINK_KEYS = {"link_cirea", "link_housing"}
|
||||
_POSITIVE = {
|
||||
"upload_max_bytes": "上传大小上限必须是正整数",
|
||||
@@ -97,41 +95,6 @@ def _logo_id(value) -> str:
|
||||
return str(int(text))
|
||||
|
||||
|
||||
def _banner_ids(value) -> str:
|
||||
if not isinstance(value, list):
|
||||
_bad("banner_file_ids 必须是数组")
|
||||
numbers: list[int] = []
|
||||
for item in value:
|
||||
if isinstance(item, bool) or not isinstance(item, (int, str)):
|
||||
_bad("banner_file_ids 必须是附件编号")
|
||||
text = str(item).strip()
|
||||
if not text.isdigit() or int(text) <= 0:
|
||||
_bad("banner_file_ids 必须是附件编号")
|
||||
numbers.append(int(text))
|
||||
return json.dumps(numbers, separators=(",", ":"))
|
||||
|
||||
|
||||
def _friend_links(value) -> str:
|
||||
if not isinstance(value, list):
|
||||
_bad("friend_links 必须是数组")
|
||||
cleaned: list[dict[str, str]] = []
|
||||
for item in value:
|
||||
if not isinstance(item, dict):
|
||||
_bad("相关链接必须包含名称和地址")
|
||||
name = item.get("name")
|
||||
url = item.get("url")
|
||||
if not isinstance(name, str) or not isinstance(url, str):
|
||||
_bad("相关链接必须包含名称和地址")
|
||||
name = name.strip()
|
||||
url = url.strip()
|
||||
if not name or not url:
|
||||
_bad("相关链接必须包含名称和地址")
|
||||
if is_javascript_url(url):
|
||||
_bad("链接地址不正确")
|
||||
cleaned.append({"name": name, "url": url})
|
||||
return json.dumps(cleaned, ensure_ascii=False, separators=(",", ":"))
|
||||
|
||||
|
||||
def _positive(value, message: str) -> str:
|
||||
if isinstance(value, bool) or not isinstance(value, int) or value <= 0 or value > _INT_MAX:
|
||||
_bad(message)
|
||||
@@ -155,10 +118,6 @@ def _normalize_settings(payload: dict) -> dict[str, str]:
|
||||
stored[key] = _text_setting(key, value)
|
||||
elif key == "logo_file_id":
|
||||
stored[key] = _logo_id(value)
|
||||
elif key == "banner_file_ids":
|
||||
stored[key] = _banner_ids(value)
|
||||
elif key == "friend_links":
|
||||
stored[key] = _friend_links(value)
|
||||
elif key in _POSITIVE:
|
||||
stored[key] = _positive(value, _POSITIVE[key])
|
||||
elif key in _WORKDAYS:
|
||||
|
||||
@@ -12,12 +12,9 @@ def read_public_settings(db: Session = Depends(get_db)) -> dict:
|
||||
# 只返回门户展示字段。上传上限和登录锁定参数留在管理端。
|
||||
data = settings_view(db)
|
||||
return {
|
||||
"siteName": data["site_name"],
|
||||
"logoUrl": data["logoUrl"],
|
||||
"bannerUrls": data["bannerUrls"],
|
||||
"icpText": data["icp_text"],
|
||||
"policeText": data["police_text"],
|
||||
"friendLinks": data["friend_links"],
|
||||
"linkCirea": data["link_cirea"],
|
||||
"linkHousing": data["link_housing"],
|
||||
}
|
||||
@@ -1,4 +1,3 @@
|
||||
import json
|
||||
from datetime import datetime, timezone
|
||||
|
||||
from sqlalchemy import DateTime, Integer, String, Text, select
|
||||
@@ -11,12 +10,9 @@ def _mysql_args() -> dict:
|
||||
return {"mysql_charset": "utf8mb4", "mysql_collate": "utf8mb4_unicode_ci"}
|
||||
|
||||
DEFAULTS: dict[str, str] = {
|
||||
"site_name": "甘肃省房地产价格评估行业协会",
|
||||
"logo_file_id": "",
|
||||
"banner_file_ids": "[]",
|
||||
"icp_text": "陇ICP备19001227号",
|
||||
"police_text": "甘公网安备62010202001984号",
|
||||
"friend_links": "[]",
|
||||
"link_cirea": "",
|
||||
"link_housing": "",
|
||||
"complaint_workdays": "",
|
||||
@@ -27,7 +23,6 @@ DEFAULTS: dict[str, str] = {
|
||||
}
|
||||
|
||||
SETTING_KEYS = tuple(DEFAULTS)
|
||||
_JSON_KEYS = {"banner_file_ids", "friend_links"}
|
||||
_NUMBER_KEYS = {"upload_max_bytes", "login_max_failures", "login_lock_minutes"}
|
||||
_OPTIONAL_NUMBER_KEYS = {"complaint_workdays", "expert_reply_workdays"}
|
||||
|
||||
@@ -109,14 +104,6 @@ def save_settings(db, values: dict[str, str]) -> None:
|
||||
|
||||
|
||||
def _present(key: str, raw: str):
|
||||
if key in _JSON_KEYS:
|
||||
if not raw:
|
||||
return []
|
||||
try:
|
||||
parsed = json.loads(raw)
|
||||
except json.JSONDecodeError:
|
||||
return []
|
||||
return parsed if isinstance(parsed, list) else []
|
||||
if key in _NUMBER_KEYS:
|
||||
text = str(raw).strip()
|
||||
if text.isdigit():
|
||||
@@ -160,6 +147,4 @@ def settings_view(db) -> dict:
|
||||
logo_id = raw.get("logo_file_id", "")
|
||||
logo_urls = _public_urls(db, [logo_id]) if str(logo_id).strip() else []
|
||||
view["logoUrl"] = logo_urls[0] if logo_urls else ""
|
||||
banners = view["banner_file_ids"] if isinstance(view["banner_file_ids"], list) else []
|
||||
view["bannerUrls"] = _public_urls(db, banners)
|
||||
return view
|
||||
@@ -301,7 +301,6 @@ def main() -> None:
|
||||
"/api/admin/site-settings",
|
||||
headers=headers,
|
||||
json={
|
||||
"site_name": "验收站点",
|
||||
"icp_text": "陇ICP备19001227号",
|
||||
"link_cirea": "https://www.cirea.org.cn/",
|
||||
},
|
||||
@@ -310,10 +309,12 @@ def main() -> None:
|
||||
fail(f"site {site.status_code} {site.text[:200]}")
|
||||
public_site = client.get("/api/site/settings")
|
||||
public_body = public_site.json()
|
||||
if public_body.get("siteName") != "验收站点" or public_body.get("linkCirea") != "https://www.cirea.org.cn/":
|
||||
if public_body.get("icpText") != "陇ICP备19001227号" or public_body.get("linkCirea") != "https://www.cirea.org.cn/":
|
||||
fail(f"public site {public_body}")
|
||||
if "loginMaxFailures" in public_body or "login_max_failures" in public_body:
|
||||
fail("public site leaked lock settings")
|
||||
if "siteName" in public_body or "bannerUrls" in public_body or "friendLinks" in public_body:
|
||||
fail(f"public site kept removed keys {public_body}")
|
||||
|
||||
probe_word = f"验收敏感词{uuid.uuid4().hex[:6]}"
|
||||
word = client.post("/api/admin/sensitive-words", headers=headers, json={"word": probe_word})
|
||||
@@ -340,7 +341,7 @@ def main() -> None:
|
||||
client.put(
|
||||
"/api/admin/site-settings",
|
||||
headers=headers,
|
||||
json={"site_name": "甘肃省房地产价格评估行业协会", "link_cirea": ""},
|
||||
json={"link_cirea": ""},
|
||||
)
|
||||
|
||||
db = SessionLocal()
|
||||
|
||||
@@ -13,12 +13,9 @@ from app.core.config import get_settings
|
||||
from app.services.html_filter import filter_html
|
||||
|
||||
_PUBLIC_KEYS = {
|
||||
"siteName",
|
||||
"logoUrl",
|
||||
"bannerUrls",
|
||||
"icpText",
|
||||
"policeText",
|
||||
"friendLinks",
|
||||
"linkCirea",
|
||||
"linkHousing",
|
||||
}
|
||||
@@ -224,7 +221,7 @@ def test_admin_content_requires_login(api_client):
|
||||
("get", "/api/admin/files/1", None),
|
||||
("get", "/api/admin/site-settings", None),
|
||||
("get", "/api/admin/sensitive-words", None),
|
||||
("put", "/api/admin/site-settings", {"site_name": "x"}),
|
||||
("put", "/api/admin/site-settings", {"icp_text": "x"}),
|
||||
("post", "/api/admin/sensitive-words", {"word": "x"}),
|
||||
("post", "/api/admin/content/preview-filter", {"html": "<p>a</p>"}),
|
||||
("delete", "/api/admin/sensitive-words/1", None),
|
||||
@@ -309,8 +306,6 @@ def test_public_settings_hide_login_lock(ready_client):
|
||||
assert isinstance(original["login_max_failures"], int)
|
||||
assert isinstance(original["login_lock_minutes"], int)
|
||||
assert isinstance(original["logoUrl"], str)
|
||||
assert isinstance(original["bannerUrls"], list)
|
||||
link = {"name": "示例链接", "url": "https://example.com/gsrea"}
|
||||
try:
|
||||
rejected = ready_client.put(
|
||||
"/api/admin/site-settings",
|
||||
@@ -318,12 +313,17 @@ def test_public_settings_hide_login_lock(ready_client):
|
||||
headers=headers,
|
||||
)
|
||||
assert rejected.status_code == 400
|
||||
unknown = ready_client.put(
|
||||
"/api/admin/site-settings",
|
||||
json={"site_name": "甘肃价协测试站点"},
|
||||
headers=headers,
|
||||
)
|
||||
assert unknown.status_code == 400
|
||||
saved = ready_client.put(
|
||||
"/api/admin/site-settings",
|
||||
json={
|
||||
"site_name": "甘肃价协测试站点",
|
||||
"icp_text": "陇ICP备测试号",
|
||||
"friend_links": [link],
|
||||
"link_cirea": "https://example.com/cirea",
|
||||
},
|
||||
headers=headers,
|
||||
)
|
||||
@@ -332,11 +332,9 @@ def test_public_settings_hide_login_lock(ready_client):
|
||||
assert response.status_code == 200, response.text
|
||||
body = response.json()
|
||||
assert set(body) == _PUBLIC_KEYS
|
||||
assert body["siteName"] == "甘肃价协测试站点"
|
||||
assert body["icpText"] == "陇ICP备测试号"
|
||||
assert body["friendLinks"] == [link]
|
||||
assert body["linkCirea"] == "https://example.com/cirea"
|
||||
assert isinstance(body["logoUrl"], str)
|
||||
assert isinstance(body["bannerUrls"], list)
|
||||
text = response.text
|
||||
assert "login_max_failures" not in text
|
||||
assert "login_lock_minutes" not in text
|
||||
@@ -344,13 +342,15 @@ def test_public_settings_hide_login_lock(ready_client):
|
||||
assert "loginLockMinutes" not in text
|
||||
assert "upload_max_bytes" not in text
|
||||
assert "uploadMaxBytes" not in text
|
||||
assert "siteName" not in text
|
||||
assert "bannerUrls" not in text
|
||||
assert "friendLinks" not in text
|
||||
finally:
|
||||
ready_client.put(
|
||||
"/api/admin/site-settings",
|
||||
json={
|
||||
"site_name": original["site_name"],
|
||||
"icp_text": original["icp_text"],
|
||||
"friend_links": original["friend_links"],
|
||||
"link_cirea": original["link_cirea"],
|
||||
},
|
||||
headers=headers,
|
||||
)
|
||||
|
||||
Reference in new issue
Block a user