|
@@ -41,6 +41,7 @@ for dir_path in [
|
|
|
config.GENERATED_FOLDER,
|
|
config.GENERATED_FOLDER,
|
|
|
config.POSTS_DATA_FOLDER,
|
|
config.POSTS_DATA_FOLDER,
|
|
|
config.INDEX_FILE.parent,
|
|
config.INDEX_FILE.parent,
|
|
|
|
|
+ config.UPLOAD_FOLDER / "editor_uploads",
|
|
|
]:
|
|
]:
|
|
|
dir_path.mkdir(parents=True, exist_ok=True)
|
|
dir_path.mkdir(parents=True, exist_ok=True)
|
|
|
|
|
|
|
@@ -82,6 +83,116 @@ def logout():
|
|
|
return redirect(url_for("index"))
|
|
return redirect(url_for("index"))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
+# ==================== 编辑器相关路由 ====================
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+@app.route("/editor", methods=["GET", "POST"])
|
|
|
|
|
+def editor():
|
|
|
|
|
+ """Markdown 编辑器页面:创建新文章(需要登录)"""
|
|
|
|
|
+ if "user" not in session:
|
|
|
|
|
+ flash("请先登录", "warning")
|
|
|
|
|
+ return redirect(url_for("login"))
|
|
|
|
|
+
|
|
|
|
|
+ if request.method == "GET":
|
|
|
|
|
+ return render_template("editor.html")
|
|
|
|
|
+
|
|
|
|
|
+ # POST:保存文章
|
|
|
|
|
+ title = request.form.get("title", "").strip()
|
|
|
|
|
+ if not title:
|
|
|
|
|
+ flash("标题不能为空", "danger")
|
|
|
|
|
+ return redirect(url_for("editor"))
|
|
|
|
|
+
|
|
|
|
|
+ md_content = request.form.get("content", "")
|
|
|
|
|
+ if not md_content.strip():
|
|
|
|
|
+ flash("内容不能为空", "danger")
|
|
|
|
|
+ return redirect(url_for("editor"))
|
|
|
|
|
+
|
|
|
|
|
+ # 生成唯一文章 ID
|
|
|
|
|
+ post_id = str(int(time.time() * 1000))
|
|
|
|
|
+
|
|
|
|
|
+ # 确保文章数据目录存在
|
|
|
|
|
+ posts_data_dir = config.POSTS_DATA_FOLDER / post_id
|
|
|
|
|
+ posts_data_dir.mkdir(parents=True, exist_ok=True)
|
|
|
|
|
+
|
|
|
|
|
+ # 保存 Markdown 文件
|
|
|
|
|
+ md_path = posts_data_dir / "content.md"
|
|
|
|
|
+ with open(md_path, "w", encoding="utf-8") as f:
|
|
|
|
|
+ f.write(md_content)
|
|
|
|
|
+
|
|
|
|
|
+ # 修正图片路径(允许 http、/ 开头路径保持原样)
|
|
|
|
|
+ fixed_md = fix_image_paths(md_content, post_id)
|
|
|
|
|
+
|
|
|
|
|
+ # 渲染 HTML
|
|
|
|
|
+ html_body = render_markdown(fixed_md)
|
|
|
|
|
+
|
|
|
|
|
+ # 提取摘要与缩略图
|
|
|
|
|
+ summary = extract_summary(html_body)
|
|
|
|
|
+ thumbnail = extract_thumbnail(html_body)
|
|
|
|
|
+
|
|
|
|
|
+ # 生成日期(精确到分钟)
|
|
|
|
|
+ date_iso = datetime.now(timezone.utc).replace(second=0, microsecond=0).isoformat()
|
|
|
|
|
+
|
|
|
|
|
+ # 生成静态页面
|
|
|
|
|
+ generate_static_page(post_id, title, html_body, date_iso, thumbnail)
|
|
|
|
|
+
|
|
|
|
|
+ # 更新索引
|
|
|
|
|
+ index = load_index()
|
|
|
|
|
+ index.append(
|
|
|
|
|
+ {
|
|
|
|
|
+ "id": post_id,
|
|
|
|
|
+ "title": title,
|
|
|
|
|
+ "date": date_iso,
|
|
|
|
|
+ "summary": summary,
|
|
|
|
|
+ "thumbnail": thumbnail,
|
|
|
|
|
+ }
|
|
|
|
|
+ )
|
|
|
|
|
+ index.sort(key=lambda p: p.get("date", ""), reverse=True)
|
|
|
|
|
+ save_index(index)
|
|
|
|
|
+
|
|
|
|
|
+ flash("文章发布成功", "success")
|
|
|
|
|
+ return redirect(url_for("index"))
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+@app.route("/editor/upload-image", methods=["POST"])
|
|
|
|
|
+def editor_upload_image():
|
|
|
|
|
+ """处理编辑器中的图片上传,返回 Markdown 图片代码"""
|
|
|
|
|
+ if "user" not in session:
|
|
|
|
|
+ return jsonify({"success": False, "error": "需要登录"}), 403
|
|
|
|
|
+
|
|
|
|
|
+ if "image" not in request.files:
|
|
|
|
|
+ return jsonify({"success": False, "error": "没有选择图片"}), 400
|
|
|
|
|
+
|
|
|
|
|
+ file = request.files["image"]
|
|
|
|
|
+ if file.filename == "":
|
|
|
|
|
+ return jsonify({"success": False, "error": "文件名为空"}), 400
|
|
|
|
|
+
|
|
|
|
|
+ # 只允许图片类型
|
|
|
|
|
+ if not allowed_file(file.filename):
|
|
|
|
|
+ return jsonify({"success": False, "error": "不支持的文件类型"}), 400
|
|
|
|
|
+
|
|
|
|
|
+ # 保存到 editor_uploads 目录
|
|
|
|
|
+ editor_uploads_dir = config.UPLOAD_FOLDER / "editor_uploads"
|
|
|
|
|
+ editor_uploads_dir.mkdir(parents=True, exist_ok=True)
|
|
|
|
|
+
|
|
|
|
|
+ safe_name = secure_filename(file.filename)
|
|
|
|
|
+ timestamp = str(int(time.time() * 1000))
|
|
|
|
|
+ new_name = f"{timestamp}_{safe_name}"
|
|
|
|
|
+ file_path = editor_uploads_dir / new_name
|
|
|
|
|
+ file.save(str(file_path))
|
|
|
|
|
+
|
|
|
|
|
+ # 生成可访问 URL 和 Markdown 片段
|
|
|
|
|
+ image_url = f"/static/uploads/posts/editor_uploads/{new_name}"
|
|
|
|
|
+ markdown_code = f""
|
|
|
|
|
+
|
|
|
|
|
+ return jsonify(
|
|
|
|
|
+ {
|
|
|
|
|
+ "success": True,
|
|
|
|
|
+ "url": image_url,
|
|
|
|
|
+ "markdown": markdown_code,
|
|
|
|
|
+ }
|
|
|
|
|
+ )
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
# ==================== 路由 ====================
|
|
# ==================== 路由 ====================
|
|
|
|
|
|
|
|
|
|
|
|
@@ -129,7 +240,7 @@ def index():
|
|
|
|
|
|
|
|
@app.route("/upload", methods=["GET", "POST"])
|
|
@app.route("/upload", methods=["GET", "POST"])
|
|
|
def upload():
|
|
def upload():
|
|
|
- """上传文章(需要登录)"""
|
|
|
|
|
|
|
+ """上传文章(原始文件上传,需要登录)"""
|
|
|
# 登录检查
|
|
# 登录检查
|
|
|
if "user" not in session:
|
|
if "user" not in session:
|
|
|
flash("请先登录", "warning")
|
|
flash("请先登录", "warning")
|