e1ba31afda
- 修复system.py缩进错误 - 优化前端页面样式(待重构) - 改进API接口结构 - 完善文档和自动化脚本 - 平台基本功能稳定运行
206 lines
7.1 KiB
Python
206 lines
7.1 KiB
Python
from fastapi import APIRouter, Depends, HTTPException, Query
|
|
from sqlalchemy.orm import Session
|
|
from typing import List, Optional
|
|
from datetime import datetime, date
|
|
from pathlib import Path
|
|
|
|
from ..database import get_db
|
|
from ..models import Topic, PublishRecord
|
|
from ..schemas import TopicResponse, PublishRequest, PublishActionRequest, PublishRecordResponse
|
|
from .auth import get_current_user
|
|
|
|
router = APIRouter(prefix="/api/topics", tags=["topics"], dependencies=[Depends(get_current_user)])
|
|
|
|
PROJECT_ROOT = Path(__file__).parent.parent.parent
|
|
|
|
@router.get("", response_model=List[TopicResponse])
|
|
def list_topics(
|
|
status: str = None,
|
|
db: Session = Depends(get_db)
|
|
):
|
|
# 确保读取最新数据,清除会话缓存
|
|
db.expire_all()
|
|
query = db.query(Topic)
|
|
if status:
|
|
query = query.filter(Topic.status == status)
|
|
topics = query.order_by(Topic.priority_score.desc(), Topic.created_at.desc()).all()
|
|
return topics
|
|
|
|
@router.get("/{topic_id}", response_model=TopicResponse)
|
|
def get_topic(topic_id: str, db: Session = Depends(get_db)):
|
|
topic = db.query(Topic).filter(Topic.id == topic_id).first()
|
|
if not topic:
|
|
raise HTTPException(status_code=404, detail="Topic not found")
|
|
return topic
|
|
|
|
@router.post("/{topic_id}/publish")
|
|
def publish_topic(topic_id: str, req: PublishRequest, db: Session = Depends(get_db)):
|
|
topic = db.query(Topic).filter(Topic.id == topic_id).first()
|
|
if not topic:
|
|
raise HTTPException(status_code=404, detail="Topic not found")
|
|
if topic.status != "ready":
|
|
raise HTTPException(status_code=400, detail="Topic not in ready status")
|
|
|
|
# 更新选题状态
|
|
topic.status = "published"
|
|
topic.published_at = datetime.now().date()
|
|
topic.updated_at = datetime.now()
|
|
topic.platform_urls = req.platform_urls
|
|
db.commit()
|
|
|
|
# 创建发布记录
|
|
record = PublishRecord(
|
|
topic_id=topic_id,
|
|
platform=req.platform,
|
|
action="publish",
|
|
status="success",
|
|
operator=req.operator,
|
|
description=req.description,
|
|
suggestion=req.suggestion,
|
|
url=req.url,
|
|
error_msg=req.error_msg
|
|
)
|
|
db.add(record)
|
|
db.commit()
|
|
db.refresh(record)
|
|
|
|
return {"message": "Topic marked as published", "topic_id": topic_id, "record_id": record.id}
|
|
|
|
|
|
# 获取选题的发布记录
|
|
@router.get("/{topic_id}/publish-records", response_model=List[PublishRecordResponse])
|
|
def get_publish_records(topic_id: str, db: Session = Depends(get_db)):
|
|
records = db.query(PublishRecord).filter(PublishRecord.topic_id == topic_id).order_by(PublishRecord.created_at.desc()).all()
|
|
return records
|
|
|
|
|
|
# 创建新的发布记录(用于手动记录发布情况)
|
|
@router.post("/{topic_id}/publish-records")
|
|
def create_publish_record(topic_id: str, req: PublishActionRequest, db: Session = Depends(get_db)):
|
|
# 验证选题存在
|
|
topic = db.query(Topic).filter(Topic.id == topic_id).first()
|
|
if not topic:
|
|
raise HTTPException(status_code=404, detail="Topic not found")
|
|
|
|
record = PublishRecord(
|
|
topic_id=topic_id,
|
|
platform=req.platform or "unknown",
|
|
action=req.action,
|
|
status=req.status,
|
|
operator=req.operator,
|
|
description=req.description,
|
|
suggestion=req.suggestion,
|
|
url=req.url,
|
|
error_msg=req.error_msg
|
|
)
|
|
db.add(record)
|
|
db.commit()
|
|
db.refresh(record)
|
|
|
|
# 如果操作是发布成功,且platform指定,则更新topic的platform_urls
|
|
if req.action == "publish" and req.status == "success" and req.platform and req.url:
|
|
if not topic.platform_urls:
|
|
topic.platform_urls = {}
|
|
topic.platform_urls[req.platform] = req.url
|
|
db.commit()
|
|
|
|
return record
|
|
|
|
|
|
# 更新发布记录
|
|
@router.put("/publish-records/{record_id}")
|
|
def update_publish_record(record_id: int, req: PublishActionRequest, db: Session = Depends(get_db)):
|
|
record = db.query(PublishRecord).filter(PublishRecord.id == record_id).first()
|
|
if not record:
|
|
raise HTTPException(status_code=404, detail="Record not found")
|
|
|
|
# 更新字段
|
|
for field, value in req.dict(exclude_unset=True).items():
|
|
setattr(record, field, value)
|
|
record.updated_at = datetime.now()
|
|
db.commit()
|
|
|
|
return record
|
|
|
|
|
|
@router.get("/{topic_id}/preview")
|
|
def preview_topic(topic_id: str, platform: str = Query("zhihu", regex="^(zhihu|wechat|xiaohongshu)$")):
|
|
"""
|
|
预览某选题在指定平台的HTML内容。
|
|
查找最近发布的release文件。
|
|
"""
|
|
# 查找最近的发布包
|
|
releases_dir = PROJECT_ROOT / "automation" / "data" / "releases"
|
|
if not releases_dir.exists():
|
|
raise HTTPException(status_code=404, detail="No releases found")
|
|
|
|
# 按日期倒序查找
|
|
dates = sorted([d.name for d in releases_dir.iterdir() if d.is_dir()], reverse=True)
|
|
found = None
|
|
for dt in dates:
|
|
file_path = releases_dir / dt / platform / f"{platform}_{topic_id}_{platform}.html"
|
|
if file_path.exists():
|
|
found = file_path
|
|
break
|
|
|
|
if not found:
|
|
raise HTTPException(status_code=404, detail=f"Preview not found for topic {topic_id} on {platform}")
|
|
|
|
content = found.read_text(encoding="utf-8")
|
|
return {"topic_id": topic_id, "platform": platform, "html": content}
|
|
|
|
|
|
@router.get("/{topic_id}/packages")
|
|
def list_packages(topic_id: str):
|
|
"""
|
|
列出某选题的所有发布包(HTML文件)。
|
|
"""
|
|
releases_dir = PROJECT_ROOT / "automation" / "data" / "releases"
|
|
if not releases_dir.exists():
|
|
return {"packages": []}
|
|
|
|
packages = []
|
|
dates = sorted([d.name for d in releases_dir.iterdir() if d.is_dir()], reverse=True)
|
|
for dt in dates:
|
|
date_dir = releases_dir / dt
|
|
for platform in ["zhihu", "wechat", "xiaohongshu"]:
|
|
file_path = date_dir / platform / f"{platform}_{topic_id}_{platform}.html"
|
|
if file_path.exists():
|
|
stat = file_path.stat()
|
|
packages.append({
|
|
"platform": platform,
|
|
"path": str(file_path.relative_to(PROJECT_ROOT)),
|
|
"size": stat.st_size,
|
|
"modified": datetime.fromtimestamp(stat.st_mtime).isoformat()
|
|
})
|
|
|
|
return {"packages": packages}
|
|
|
|
|
|
@router.post("/{topic_id}/packages/generate")
|
|
def generate_packages(topic_id: str):
|
|
"""
|
|
手动触发单个选题的发布包生成。
|
|
相当于执行 publisher.py 针对单个选题。
|
|
"""
|
|
from ..core.publisher import run_publisher
|
|
result = run_publisher(topic_id)
|
|
if not result["ok"]:
|
|
raise HTTPException(status_code=500, detail=result["error"])
|
|
return {
|
|
"message": f"Package generation completed for topic {topic_id}",
|
|
"topic_id": topic_id,
|
|
"output": result.get("result", "")
|
|
}
|
|
|
|
@router.delete("/{topic_id}")
|
|
def delete_topic(topic_id: str, db: Session = Depends(get_db)):
|
|
"""删除选题"""
|
|
topic = db.query(Topic).filter(Topic.id == topic_id).first()
|
|
if not topic:
|
|
raise HTTPException(status_code=404, detail="选题不存在")
|
|
|
|
db.delete(topic)
|
|
db.commit()
|
|
return {"message": "删除成功", "topic_id": topic_id}
|