259 lines
6.8 KiB
Python
259 lines
6.8 KiB
Python
"""
|
|
CMS 数据库操作工具 — 草稿文章查找、内容更新
|
|
|
|
用法:
|
|
from cms_ops import find_draft_by_title, update_article_content
|
|
"""
|
|
|
|
import sqlite3
|
|
import os
|
|
from datetime import datetime
|
|
from typing import Optional, List, Dict, Any
|
|
|
|
# 数据库路径(相对脚本所在目录)
|
|
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
|
|
PROJECT_ROOT = os.path.dirname(SCRIPT_DIR) # website-new 根目录
|
|
DB_PATH = os.path.join(PROJECT_ROOT, "backend", "cms.db")
|
|
|
|
|
|
def _get_conn():
|
|
"""获取数据库连接"""
|
|
conn = sqlite3.connect(DB_PATH)
|
|
conn.row_factory = sqlite3.Row
|
|
return conn
|
|
|
|
|
|
def find_draft_by_title(keyword: str) -> Optional[Dict[str, Any]]:
|
|
"""
|
|
按标题关键词查找最新一篇草稿文章。
|
|
|
|
Args:
|
|
keyword: 标题关键词
|
|
|
|
Returns:
|
|
文章字典,未找到返回 None
|
|
"""
|
|
conn = _get_conn()
|
|
cursor = conn.cursor()
|
|
cursor.execute(
|
|
"""SELECT * FROM articles
|
|
WHERE status = 'draft' AND title LIKE ?
|
|
ORDER BY created_at DESC
|
|
LIMIT 1""",
|
|
(f"%{keyword}%",),
|
|
)
|
|
row = cursor.fetchone()
|
|
conn.close()
|
|
if row:
|
|
return dict(row)
|
|
return None
|
|
|
|
|
|
def find_draft_by_column(column_name: str) -> Optional[Dict[str, Any]]:
|
|
"""
|
|
查找某栏目下最新一篇草稿文章。
|
|
|
|
Args:
|
|
column_name: 栏目名称(模糊匹配)
|
|
|
|
Returns:
|
|
文章字典,未找到返回 None
|
|
"""
|
|
conn = _get_conn()
|
|
cursor = conn.cursor()
|
|
cursor.execute(
|
|
"""SELECT articles.* FROM articles
|
|
JOIN columns ON articles.column_id = columns.id
|
|
WHERE articles.status = 'draft' AND columns.name LIKE ?
|
|
ORDER BY articles.created_at DESC
|
|
LIMIT 1""",
|
|
(f"%{column_name}%",),
|
|
)
|
|
row = cursor.fetchone()
|
|
conn.close()
|
|
if row:
|
|
return dict(row)
|
|
return None
|
|
|
|
|
|
def find_draft_by_id(article_id: int) -> Optional[Dict[str, Any]]:
|
|
"""
|
|
按 ID 查找草稿文章。
|
|
|
|
Args:
|
|
article_id: 文章 ID
|
|
|
|
Returns:
|
|
文章字典,未找到返回 None
|
|
"""
|
|
conn = _get_conn()
|
|
cursor = conn.cursor()
|
|
cursor.execute(
|
|
"SELECT * FROM articles WHERE id = ? AND status = 'draft'",
|
|
(article_id,),
|
|
)
|
|
row = cursor.fetchone()
|
|
conn.close()
|
|
if row:
|
|
return dict(row)
|
|
return None
|
|
|
|
|
|
def list_latest_drafts(limit: int = 10) -> List[Dict[str, Any]]:
|
|
"""
|
|
列出最新的 N 篇草稿文章。
|
|
|
|
Args:
|
|
limit: 返回数量
|
|
|
|
Returns:
|
|
文章字典列表
|
|
"""
|
|
conn = _get_conn()
|
|
cursor = conn.cursor()
|
|
cursor.execute(
|
|
"""SELECT id, title, column_id, content_type,
|
|
length(content) as content_len, created_at
|
|
FROM articles
|
|
WHERE status = 'draft'
|
|
ORDER BY created_at DESC
|
|
LIMIT ?""",
|
|
(limit,),
|
|
)
|
|
rows = cursor.fetchall()
|
|
conn.close()
|
|
return [dict(r) for r in rows]
|
|
|
|
|
|
def get_article_full(article_id: int) -> Optional[Dict[str, Any]]:
|
|
"""
|
|
获取文章完整内容(不限制状态)。
|
|
|
|
Args:
|
|
article_id: 文章 ID
|
|
|
|
Returns:
|
|
文章字典,包含 content 字段
|
|
"""
|
|
conn = _get_conn()
|
|
cursor = conn.cursor()
|
|
cursor.execute("SELECT * FROM articles WHERE id = ?", (article_id,))
|
|
row = cursor.fetchone()
|
|
conn.close()
|
|
if row:
|
|
return dict(row)
|
|
return None
|
|
|
|
|
|
def update_article_content(
|
|
article_id: int,
|
|
new_content: str,
|
|
status: str = "published",
|
|
new_title: Optional[str] = None,
|
|
new_author: Optional[str] = None,
|
|
new_cover_image: Optional[str] = None,
|
|
) -> bool:
|
|
"""
|
|
更新文章内容、状态和可选的标题/作者/封面图。
|
|
|
|
Args:
|
|
article_id: 文章 ID
|
|
new_content: 改写后的正文
|
|
status: 新状态,默认 'published'
|
|
new_title: 可选,改写后的标题
|
|
new_author: 可选,改写后的作者
|
|
new_cover_image: 可选,新的封面图路径
|
|
|
|
Returns:
|
|
是否更新成功
|
|
"""
|
|
conn = _get_conn()
|
|
cursor = conn.cursor()
|
|
now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
|
|
|
sets = ["content = ?", "status = ?", "updated_at = ?"]
|
|
params = [new_content, status, now]
|
|
|
|
if new_title:
|
|
sets.append("title = ?")
|
|
params.append(new_title)
|
|
|
|
if new_author:
|
|
sets.append("author = ?")
|
|
params.append(new_author)
|
|
|
|
if new_cover_image:
|
|
sets.append("cover_image = ?")
|
|
params.append(new_cover_image)
|
|
|
|
params.append(article_id)
|
|
cursor.execute(
|
|
f"UPDATE articles SET {', '.join(sets)} WHERE id = ?",
|
|
params,
|
|
)
|
|
|
|
conn.commit()
|
|
affected = cursor.rowcount
|
|
conn.close()
|
|
return affected > 0
|
|
|
|
|
|
def count_drafts() -> int:
|
|
"""统计草稿文章数量"""
|
|
conn = _get_conn()
|
|
cursor = conn.cursor()
|
|
cursor.execute("SELECT COUNT(*) FROM articles WHERE status = 'draft'")
|
|
count = cursor.fetchone()[0]
|
|
conn.close()
|
|
return count
|
|
|
|
|
|
# ---- 命令行模式 ----
|
|
if __name__ == "__main__":
|
|
import sys
|
|
|
|
if len(sys.argv) < 2:
|
|
print("用法:")
|
|
print(" python cms_ops.py list [limit] 列表最新草稿")
|
|
print(" python cms_ops.py search <keyword> 按标题搜索")
|
|
print(" python cms_ops.py get <id> 获取文章完整内容")
|
|
print(" python cms_ops.py count 统计草稿数量")
|
|
sys.exit(0)
|
|
|
|
cmd = sys.argv[1]
|
|
|
|
if cmd == "list":
|
|
limit = int(sys.argv[2]) if len(sys.argv) > 2 else 10
|
|
drafts = list_latest_drafts(limit)
|
|
print(f"最新 {len(drafts)} 篇草稿:\n")
|
|
for d in drafts:
|
|
title = d["title"][:50]
|
|
print(f" ID={d['id']:<5} | {title:<50s} | {d['content_len']} chars | {d['created_at']}")
|
|
|
|
elif cmd == "search":
|
|
keyword = sys.argv[2]
|
|
article = find_draft_by_title(keyword)
|
|
if article:
|
|
print(f"找到: ID={article['id']} | {article['title']}")
|
|
print(f"内容类型: {article['content_type']}")
|
|
print(f"内容长度: {len(article.get('content', ''))} chars")
|
|
print(f"摘要: {article.get('summary', '')}")
|
|
print(f"\n正文:\n{article.get('content', '')[:500]}...")
|
|
else:
|
|
print(f"未找到匹配 '{keyword}' 的草稿")
|
|
|
|
elif cmd == "get":
|
|
article_id = int(sys.argv[2])
|
|
article = get_article_full(article_id)
|
|
if article:
|
|
print(f"ID={article['id']} | {article['title']}")
|
|
print(f"状态: {article['status']}")
|
|
print(f"内容类型: {article['content_type']}")
|
|
print(f"封面: {article.get('cover_image', '')}")
|
|
print(f"\n正文:\n{article.get('content', '')}")
|
|
else:
|
|
print(f"找不到 ID={article_id} 的文章")
|
|
|
|
elif cmd == "count":
|
|
print(f"草稿文章: {count_drafts()} 篇")
|