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.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}