from fastapi import APIRouter, Depends, HTTPException, Query from sqlalchemy.orm import Session from typing import List, Optional from datetime import datetime, date from calendar import monthrange from ..database import get_db from ..models import ContentCalendar, Topic from ..schemas import ( ContentCalendarCreate, ContentCalendarUpdate, ContentCalendarResponse, ContentCalendarBase ) from .auth import get_current_user router = APIRouter(prefix="/api/calendar", tags=["calendar"]) @router.get("", response_model=List[ContentCalendarResponse]) def get_calendar( year: Optional[int] = Query(None), month: Optional[int] = Query(None), db: Session = Depends(get_db), current_user=Depends(get_current_user) ): today = date.today() year = year or today.year month = month or today.month start = date(year, month, 1) last_day = monthrange(year, month)[1] end = date(year, month, last_day) return db.query(ContentCalendar).filter( ContentCalendar.planned_date >= start, ContentCalendar.planned_date <= end ).order_by(ContentCalendar.planned_date).all() @router.get("/entries", response_model=List[ContentCalendarResponse]) def list_entries( start_date: Optional[date] = None, end_date: Optional[date] = None, status: Optional[str] = None, platform: Optional[str] = None, limit: int = Query(50, le=200), db: Session = Depends(get_db), current_user=Depends(get_current_user) ): query = db.query(ContentCalendar) if start_date: query = query.filter(ContentCalendar.planned_date >= start_date) if end_date: query = query.filter(ContentCalendar.planned_date <= end_date) if status: query = query.filter(ContentCalendar.status == status) if platform: query = query.filter(ContentCalendar.platform == platform) return query.order_by(ContentCalendar.planned_date.desc()).limit(limit).all() @router.post("/entries", response_model=ContentCalendarResponse) def create_entry( data: ContentCalendarCreate, db: Session = Depends(get_db), current_user=Depends(get_current_user) ): if data.topic_id: topic = db.query(Topic).filter(Topic.id == data.topic_id).first() if not topic: raise HTTPException(status_code=404, detail="选题不存在") entry = ContentCalendar(**data.model_dump()) db.add(entry) db.commit() db.refresh(entry) if data.topic_id and data.title: if not topic.title or topic.title != data.title: topic.title = data.title db.commit() return entry @router.put("/entries/{entry_id}", response_model=ContentCalendarResponse) def update_entry( entry_id: int, data: ContentCalendarUpdate, db: Session = Depends(get_db), current_user=Depends(get_current_user) ): entry = db.query(ContentCalendar).filter(ContentCalendar.id == entry_id).first() if not entry: raise HTTPException(status_code=404, detail="日历条目不存在") for k, v in data.model_dump(exclude_unset=True).items(): setattr(entry, k, v) db.commit() db.refresh(entry) if entry.topic_id: topic = db.query(Topic).filter(Topic.id == entry.topic_id).first() if topic and entry.status == "published" and not entry.published_date: entry.published_date = date.today() if topic.status == "pending" or topic.status == "ready": topic.status = "published" topic.published_at = date.today() topic.updated_at = datetime.now() db.commit() return entry @router.delete("/entries/{entry_id}") def delete_entry( entry_id: int, db: Session = Depends(get_db), current_user=Depends(get_current_user) ): entry = db.query(ContentCalendar).filter(ContentCalendar.id == entry_id).first() if not entry: raise HTTPException(status_code=404, detail="日历条目不存在") db.delete(entry) db.commit() return {"ok": True} @router.post("/entries/bind-topic") def bind_topic_to_entry( entry_id: int, topic_id: str, db: Session = Depends(get_db), current_user=Depends(get_current_user) ): entry = db.query(ContentCalendar).filter(ContentCalendar.id == entry_id).first() if not entry: raise HTTPException(status_code=404, detail="日历条目不存在") topic = db.query(Topic).filter(Topic.id == topic_id).first() if not topic: raise HTTPException(status_code=404, detail="选题不存在") entry.topic_id = topic_id entry.title = topic.title if topic.field_name: entry.field_id = topic.field_id db.commit() db.refresh(entry) return entry @router.get("/stats") def calendar_stats( year: int = Query(...), month: int = Query(...), db: Session = Depends(get_db), current_user=Depends(get_current_user) ): start = date(year, month, 1) last_day = monthrange(year, month)[1] end = date(year, month, last_day) entries = db.query(ContentCalendar).filter( ContentCalendar.planned_date >= start, ContentCalendar.planned_date <= end ).all() stats = {"total": len(entries), "planned": 0, "published": 0, "delayed": 0, "cancelled": 0} for e in entries: if e.status in stats: stats[e.status] += 1 return stats @router.post("/entries/from-topic") def create_from_topic( topic_id: str, planned_date: date, platform: str = Query(...), db: Session = Depends(get_db), current_user=Depends(get_current_user) ): topic = db.query(Topic).filter(Topic.id == topic_id).first() if not topic: raise HTTPException(status_code=404, detail="选题不存在") entry = ContentCalendar( topic_id=topic_id, field_id=topic.field_id, title=topic.title, planned_date=planned_date, platform=platform, created_by=current_user.username ) db.add(entry) db.commit() db.refresh(entry) return entry