Implementación inicial del sistema de automatización de redes sociales
- Estructura completa del proyecto con FastAPI - Modelos de base de datos (productos, servicios, posts, calendario, interacciones) - Publishers para X, Threads, Instagram, Facebook - Generador de contenido con DeepSeek API - Worker de Celery con tareas programadas - Dashboard básico con templates HTML - Docker Compose para despliegue - Documentación completa Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
174
app/api/routes/services.py
Normal file
174
app/api/routes/services.py
Normal file
@@ -0,0 +1,174 @@
|
||||
"""
|
||||
API Routes para gestión de Servicios.
|
||||
"""
|
||||
|
||||
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.service import Service
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
# ===========================================
|
||||
# SCHEMAS
|
||||
# ===========================================
|
||||
|
||||
class ServiceCreate(BaseModel):
|
||||
name: str
|
||||
description: str
|
||||
short_description: Optional[str] = None
|
||||
category: str
|
||||
target_sectors: Optional[List[str]] = None
|
||||
benefits: Optional[List[str]] = None
|
||||
features: Optional[List[str]] = None
|
||||
case_studies: Optional[List[dict]] = None
|
||||
icon: Optional[str] = None
|
||||
images: Optional[List[str]] = None
|
||||
main_image: Optional[str] = None
|
||||
price_range: Optional[str] = None
|
||||
has_free_demo: bool = False
|
||||
tags: Optional[List[str]] = None
|
||||
call_to_action: Optional[str] = None
|
||||
is_featured: bool = False
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
|
||||
|
||||
class ServiceUpdate(BaseModel):
|
||||
name: Optional[str] = None
|
||||
description: Optional[str] = None
|
||||
short_description: Optional[str] = None
|
||||
category: Optional[str] = None
|
||||
target_sectors: Optional[List[str]] = None
|
||||
benefits: Optional[List[str]] = None
|
||||
features: Optional[List[str]] = None
|
||||
case_studies: Optional[List[dict]] = None
|
||||
icon: Optional[str] = None
|
||||
images: Optional[List[str]] = None
|
||||
main_image: Optional[str] = None
|
||||
price_range: Optional[str] = None
|
||||
has_free_demo: Optional[bool] = None
|
||||
tags: Optional[List[str]] = None
|
||||
call_to_action: Optional[str] = None
|
||||
is_active: Optional[bool] = None
|
||||
is_featured: Optional[bool] = None
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
|
||||
|
||||
# ===========================================
|
||||
# ENDPOINTS
|
||||
# ===========================================
|
||||
|
||||
@router.get("/")
|
||||
async def list_services(
|
||||
category: Optional[str] = Query(None),
|
||||
target_sector: Optional[str] = Query(None),
|
||||
is_active: Optional[bool] = Query(True),
|
||||
is_featured: Optional[bool] = Query(None),
|
||||
limit: int = Query(50, le=100),
|
||||
offset: int = Query(0),
|
||||
db: Session = Depends(get_db)
|
||||
):
|
||||
"""Listar servicios con filtros."""
|
||||
query = db.query(Service)
|
||||
|
||||
if category:
|
||||
query = query.filter(Service.category == category)
|
||||
if is_active is not None:
|
||||
query = query.filter(Service.is_active == is_active)
|
||||
if is_featured is not None:
|
||||
query = query.filter(Service.is_featured == is_featured)
|
||||
if target_sector:
|
||||
query = query.filter(Service.target_sectors.contains([target_sector]))
|
||||
|
||||
services = query.order_by(Service.created_at.desc()).offset(offset).limit(limit).all()
|
||||
return [s.to_dict() for s in services]
|
||||
|
||||
|
||||
@router.get("/categories")
|
||||
async def list_categories(db: Session = Depends(get_db)):
|
||||
"""Listar categorías únicas de servicios."""
|
||||
categories = db.query(Service.category).distinct().all()
|
||||
return [c[0] for c in categories if c[0]]
|
||||
|
||||
|
||||
@router.get("/featured")
|
||||
async def list_featured_services(db: Session = Depends(get_db)):
|
||||
"""Listar servicios destacados."""
|
||||
services = db.query(Service).filter(
|
||||
Service.is_featured == True,
|
||||
Service.is_active == True
|
||||
).all()
|
||||
return [s.to_dict() for s in services]
|
||||
|
||||
|
||||
@router.get("/{service_id}")
|
||||
async def get_service(service_id: int, db: Session = Depends(get_db)):
|
||||
"""Obtener un servicio por ID."""
|
||||
service = db.query(Service).filter(Service.id == service_id).first()
|
||||
if not service:
|
||||
raise HTTPException(status_code=404, detail="Servicio no encontrado")
|
||||
return service.to_dict()
|
||||
|
||||
|
||||
@router.post("/")
|
||||
async def create_service(service_data: ServiceCreate, db: Session = Depends(get_db)):
|
||||
"""Crear un nuevo servicio."""
|
||||
service = Service(**service_data.dict())
|
||||
db.add(service)
|
||||
db.commit()
|
||||
db.refresh(service)
|
||||
return service.to_dict()
|
||||
|
||||
|
||||
@router.put("/{service_id}")
|
||||
async def update_service(service_id: int, service_data: ServiceUpdate, db: Session = Depends(get_db)):
|
||||
"""Actualizar un servicio."""
|
||||
service = db.query(Service).filter(Service.id == service_id).first()
|
||||
if not service:
|
||||
raise HTTPException(status_code=404, detail="Servicio no encontrado")
|
||||
|
||||
update_data = service_data.dict(exclude_unset=True)
|
||||
for field, value in update_data.items():
|
||||
setattr(service, field, value)
|
||||
|
||||
service.updated_at = datetime.utcnow()
|
||||
db.commit()
|
||||
db.refresh(service)
|
||||
return service.to_dict()
|
||||
|
||||
|
||||
@router.delete("/{service_id}")
|
||||
async def delete_service(service_id: int, db: Session = Depends(get_db)):
|
||||
"""Eliminar un servicio."""
|
||||
service = db.query(Service).filter(Service.id == service_id).first()
|
||||
if not service:
|
||||
raise HTTPException(status_code=404, detail="Servicio no encontrado")
|
||||
|
||||
db.delete(service)
|
||||
db.commit()
|
||||
return {"message": "Servicio eliminado", "service_id": service_id}
|
||||
|
||||
|
||||
@router.post("/{service_id}/toggle-featured")
|
||||
async def toggle_featured(service_id: int, db: Session = Depends(get_db)):
|
||||
"""Alternar estado de servicio destacado."""
|
||||
service = db.query(Service).filter(Service.id == service_id).first()
|
||||
if not service:
|
||||
raise HTTPException(status_code=404, detail="Servicio no encontrado")
|
||||
|
||||
service.is_featured = not service.is_featured
|
||||
db.commit()
|
||||
|
||||
return {
|
||||
"message": f"Servicio {'destacado' if service.is_featured else 'no destacado'}",
|
||||
"is_featured": service.is_featured
|
||||
}
|
||||
Reference in New Issue
Block a user