Browse Source

feat: 添加删除文章入口

Co-authored-by: aider (deepseek/deepseek-v4-pro) <aider@aider.chat>
Your Name 3 ngày trước cách đây
mục cha
commit
efe38e4d00
3 tập tin đã thay đổi với 57 bổ sung11 xóa
  1. 49 10
      app.py
  2. 3 1
      helpers.py
  3. 5 0
      templates/post_template.html

+ 49 - 10
app.py

@@ -363,19 +363,53 @@ def upload():
 
 @app.route("/post/<post_id>")
 def view_post(post_id: str):
-    """查看文章详情"""
-    # 安全验证:只允许字母数字和下划线
+    """查看文章详情,支持登录后显示删除按钮"""
     if not re.match(r"^[a-zA-Z0-9_]+$", post_id):
         abort(404)
 
-    try:
-        return send_from_directory(
-            config.GENERATED_FOLDER,
-            f"{post_id}.html",
-        )
-    except FileNotFoundError:
+    posts = load_index()
+    entry = next((p for p in posts if p["id"] == post_id), None)
+    if not entry:
         abort(404)
 
+    title = entry.get("title", "")
+    date = entry.get("date", "")
+    thumbnail = entry.get("thumbnail", "")
+
+    content = ""
+    md_path = config.POSTS_DATA_FOLDER / post_id / "content.md"
+    if md_path.exists():
+        try:
+            with open(md_path, "r", encoding="utf-8") as f:
+                md_content = f.read()
+            fixed_md = fix_image_paths(md_content, post_id)
+            html_body = render_markdown(fixed_md)
+            content = html_body
+        except Exception:
+            content = ""
+
+    if not content:
+        generated_path = config.GENERATED_FOLDER / f"{post_id}.html"
+        if generated_path.exists():
+            try:
+                with open(generated_path, "r", encoding="utf-8") as f:
+                    html_content = f.read()
+                soup = BeautifulSoup(html_content, "html.parser")
+                card_summary = soup.find("div", class_="card-summary")
+                if card_summary:
+                    content = card_summary.decode_contents()
+            except Exception:
+                content = ""
+
+    return render_template(
+        "post_template.html",
+        title=title,
+        content=content,
+        date=date,
+        thumbnail=thumbnail,
+        post_id=post_id,
+    )
+
 
 @app.route("/admin")
 def admin():
@@ -386,7 +420,11 @@ def admin():
 
 @app.route("/admin/delete/<post_id>", methods=["POST"])
 def delete_post(post_id: str):
-    """删除文章"""
+    """删除文章(需要登录)"""
+    if "user" not in session:
+        flash("请先登录", "warning")
+        return redirect(url_for("login"))
+
     # 安全验证
     if not re.match(r"^[a-zA-Z0-9_]+$", post_id):
         abort(404)
@@ -411,7 +449,8 @@ def delete_post(post_id: str):
     index = [p for p in index if p["id"] != post_id]
     save_index(index)
 
-    return redirect(url_for("admin"))
+    flash("文章已删除", "success")
+    return redirect(url_for("index"))
 
 
 @app.errorhandler(404)

+ 3 - 1
helpers.py

@@ -68,7 +68,7 @@ def render_markdown(md_content: str) -> str:
     )
     return md.convert(md_content)
 
-def generate_static_page(post_id: str, title: str, html_body: str, date: str, thumbnail: str):
+def generate_static_page(post_id: str, title: str, html_body: str, date: str, thumbnail: str, logged_in: bool = False):
     """生成独立的静态 HTML 文件"""
     rendered = render_template(
         "post_template.html",
@@ -76,6 +76,8 @@ def generate_static_page(post_id: str, title: str, html_body: str, date: str, th
         content=html_body,
         date=date,
         thumbnail=thumbnail,
+        post_id=post_id,
+        logged_in=logged_in,
     )
     output_path = config.GENERATED_FOLDER / f"{post_id}.html"
     with open(output_path, "w", encoding="utf-8") as f:

+ 5 - 0
templates/post_template.html

@@ -15,6 +15,11 @@
         <div class="card-summary">
             {{ content | safe }}
         </div>
+        {% if logged_in and post_id %}
+        <form method="POST" action="{{ url_for('delete_post', post_id=post_id) }}" onsubmit="return confirm('确定要删除「{{ title }}」吗?此操作不可恢复。');" style="margin-top:1.5rem;">
+            <button type="submit" class="btn btn-danger">🗑️ 删除文章</button>
+        </form>
+        {% endif %}
     </div>
 </article>
 {% endblock %}