This commit is contained in:
2026-05-17 22:44:11 +08:00
parent 0380c01a27
commit 18fc9849a3
5 changed files with 203 additions and 57 deletions

50
main.py
View File

@@ -254,7 +254,7 @@ def api_create_page(slug: str) -> tuple[Response, int]:
@app.route("/api/save", methods=["POST"]) # type: ignore[untyped-decorator]
def api_save() -> tuple[Response, int] | Response:
"""接受 vvvebjs 的儲存請求,寫入對應專案目錄."""
"""接受 vvvebjs 的儲存或新增頁面請求,寫入對應專案目錄."""
if request.is_json:
raw: dict[str, Any] = request.get_json(force=True) or {}
body: dict[str, Any] = raw
@@ -263,15 +263,52 @@ def api_save() -> tuple[Response, int] | Response:
body = {k: (v[0] if isinstance(v, list) else v) for k, v in form.items()}
slug: str = str(body.get("slug", "")).strip()
filename: str = str(body.get("file", "")).strip()
html: str = str(body.get("html", "")).strip()
if not slug or not filename or not html:
return jsonify({"error": "缺少必要參數 slug / file / html"}), 400
if not slug:
return jsonify({"error": "缺少專案識別碼 (slug)"}), 400
if not _project_dir(slug).exists():
return jsonify({"error": "專案不存在"}), 404
# 1. 判斷是否為新增頁面請求 (含有 startTemplateUrl)
start_template_url = str(body.get("startTemplateUrl", "")).strip()
if start_template_url:
title = str(body.get("title", "")).strip() or "New Page"
# 取得安全的檔名 (只取檔名部分,例如 'about.html')
filename = Path(str(body.get("file", "untitled.html")).strip()).name
if not filename.endswith(".html"):
filename += ".html"
safe_path = _sanitize_file_path(slug, filename)
if safe_path is None:
return jsonify({"error": "不合法的頁面名稱"}), 400
if safe_path.exists():
return jsonify({"error": "頁面已存在"}), 409
# 解析並複製樣板 (定位在 static/Vvvebjs 目錄下)
template_source = BASE_DIR / "static" / "Vvvebjs" / start_template_url
if template_source.exists() and template_source.is_file():
shutil.copy(template_source, safe_path)
else:
_copy_blank_template(safe_path)
# 回傳 VvvebJS FileManager 所期待的 JSON 格式
page_name = safe_path.stem
return jsonify({
"ok": True,
"name": page_name,
"title": title,
"file": safe_path.name,
"url": f"/sites/{slug}/{safe_path.name}"
})
# 2. 一般儲存頁面請求
filename = str(body.get("file", "")).strip()
html: str = str(body.get("html", "")).strip()
if not filename or not html:
return jsonify({"error": "缺少必要參數 file / html"}), 400
safe_path = _sanitize_file_path(slug, filename)
if safe_path is None:
return jsonify({"error": "不合法的檔案路徑"}), 400
@@ -280,6 +317,7 @@ def api_save() -> tuple[Response, int] | Response:
return jsonify({"ok": True, "saved": safe_path.name})
@app.route("/sites/<slug>/<path:filename>") # type: ignore[untyped-decorator]
def serve_site_file(slug: str, filename: str) -> Response:
proj_dir = _project_dir(slug)