""" API Routes para gestión de Posts. """ from datetime import datetime from typing import List, Optional from fastapi import APIRouter, Depends, HTTPException, Query from sqlalchemy.orm import Session from pydantic import BaseModel from app.core.database import get_db from app.models.post import Post router = APIRouter() # =========================================== # SCHEMAS # =========================================== class PostCreate(BaseModel): content: str content_type: str platforms: List[str] scheduled_at: Optional[datetime] = None image_url: Optional[str] = None approval_required: bool = False hashtags: Optional[List[str]] = None class Config: from_attributes = True class PostUpdate(BaseModel): content: Optional[str] = None content_x: Optional[str] = None content_threads: Optional[str] = None content_instagram: Optional[str] = None content_facebook: Optional[str] = None platforms: Optional[List[str]] = None scheduled_at: Optional[datetime] = None status: Optional[str] = None image_url: Optional[str] = None hashtags: Optional[List[str]] = None class Config: from_attributes = True class PostResponse(BaseModel): id: int content: str content_type: str platforms: List[str] status: str scheduled_at: Optional[datetime] published_at: Optional[datetime] image_url: Optional[str] approval_required: bool created_at: datetime class Config: from_attributes = True # =========================================== # ENDPOINTS # =========================================== @router.get("/", response_model=List[PostResponse]) async def list_posts( status: Optional[str] = Query(None, description="Filtrar por estado"), content_type: Optional[str] = Query(None, description="Filtrar por tipo"), platform: Optional[str] = Query(None, description="Filtrar por plataforma"), limit: int = Query(50, le=100), offset: int = Query(0), db: Session = Depends(get_db) ): """Listar posts con filtros opcionales.""" query = db.query(Post) if status: query = query.filter(Post.status == status) if content_type: query = query.filter(Post.content_type == content_type) if platform: query = query.filter(Post.platforms.contains([platform])) posts = query.order_by(Post.created_at.desc()).offset(offset).limit(limit).all() return posts @router.get("/pending") async def list_pending_posts(db: Session = Depends(get_db)): """Listar posts pendientes de aprobación.""" posts = db.query(Post).filter( Post.status == "pending_approval" ).order_by(Post.scheduled_at.asc()).all() return [post.to_dict() for post in posts] @router.get("/scheduled") async def list_scheduled_posts(db: Session = Depends(get_db)): """Listar posts programados.""" posts = db.query(Post).filter( Post.status == "scheduled", Post.scheduled_at >= datetime.utcnow() ).order_by(Post.scheduled_at.asc()).all() return [post.to_dict() for post in posts] @router.get("/{post_id}") async def get_post(post_id: int, db: Session = Depends(get_db)): """Obtener un post por ID.""" post = db.query(Post).filter(Post.id == post_id).first() if not post: raise HTTPException(status_code=404, detail="Post no encontrado") return post.to_dict() @router.post("/", response_model=PostResponse) async def create_post(post_data: PostCreate, db: Session = Depends(get_db)): """Crear un nuevo post.""" post = Post( content=post_data.content, content_type=post_data.content_type, platforms=post_data.platforms, scheduled_at=post_data.scheduled_at, image_url=post_data.image_url, approval_required=post_data.approval_required, hashtags=post_data.hashtags, status="pending_approval" if post_data.approval_required else "scheduled" ) db.add(post) db.commit() db.refresh(post) return post @router.put("/{post_id}") async def update_post(post_id: int, post_data: PostUpdate, db: Session = Depends(get_db)): """Actualizar un post.""" post = db.query(Post).filter(Post.id == post_id).first() if not post: raise HTTPException(status_code=404, detail="Post no encontrado") update_data = post_data.dict(exclude_unset=True) for field, value in update_data.items(): setattr(post, field, value) post.updated_at = datetime.utcnow() db.commit() db.refresh(post) return post.to_dict() @router.post("/{post_id}/approve") async def approve_post(post_id: int, db: Session = Depends(get_db)): """Aprobar un post pendiente.""" post = db.query(Post).filter(Post.id == post_id).first() if not post: raise HTTPException(status_code=404, detail="Post no encontrado") if post.status != "pending_approval": raise HTTPException(status_code=400, detail="El post no está pendiente de aprobación") post.status = "scheduled" post.approved_at = datetime.utcnow() db.commit() return {"message": "Post aprobado", "post_id": post_id} @router.post("/{post_id}/reject") async def reject_post(post_id: int, db: Session = Depends(get_db)): """Rechazar un post pendiente.""" post = db.query(Post).filter(Post.id == post_id).first() if not post: raise HTTPException(status_code=404, detail="Post no encontrado") post.status = "cancelled" db.commit() return {"message": "Post rechazado", "post_id": post_id} @router.post("/{post_id}/regenerate") async def regenerate_post(post_id: int, db: Session = Depends(get_db)): """Regenerar contenido de un post con IA.""" post = db.query(Post).filter(Post.id == post_id).first() if not post: raise HTTPException(status_code=404, detail="Post no encontrado") # TODO: Implementar regeneración con DeepSeek # from app.services.content_generator import regenerate_content # new_content = await regenerate_content(post) return {"message": "Regeneración en desarrollo", "post_id": post_id} @router.delete("/{post_id}") async def delete_post(post_id: int, db: Session = Depends(get_db)): """Eliminar un post.""" post = db.query(Post).filter(Post.id == post_id).first() if not post: raise HTTPException(status_code=404, detail="Post no encontrado") db.delete(post) db.commit() return {"message": "Post eliminado", "post_id": post_id}