feat(phase-1): Complete foundation setup
- Add User model and authentication system with JWT cookies - Implement login/logout routes and protected dashboard - Add Alembic database migration configuration - Add create_admin.py script for initial user setup - Make ContentGenerator and ImageGenerator lazy-initialized - Add comprehensive API keys setup documentation - Fix startup errors when services unavailable Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -3,8 +3,9 @@ API Routes para el Dashboard.
|
||||
"""
|
||||
|
||||
from datetime import datetime, timedelta
|
||||
from typing import Optional
|
||||
from fastapi import APIRouter, Depends, Request
|
||||
from fastapi.responses import HTMLResponse
|
||||
from fastapi.responses import HTMLResponse, RedirectResponse
|
||||
from fastapi.templating import Jinja2Templates
|
||||
from sqlalchemy.orm import Session
|
||||
from sqlalchemy import func
|
||||
@@ -12,15 +13,26 @@ from sqlalchemy import func
|
||||
from app.core.database import get_db
|
||||
from app.models.post import Post
|
||||
from app.models.interaction import Interaction
|
||||
from app.models.user import User
|
||||
from app.api.routes.auth import get_current_user_from_cookie
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
templates = Jinja2Templates(directory="dashboard/templates")
|
||||
|
||||
|
||||
def require_auth(request: Request, db: Session) -> Optional[User]:
|
||||
"""Verificar autenticación. Retorna None si no está autenticado."""
|
||||
return get_current_user_from_cookie(request, db)
|
||||
|
||||
|
||||
@router.get("/", response_class=HTMLResponse)
|
||||
async def dashboard_home(request: Request, db: Session = Depends(get_db)):
|
||||
"""Página principal del dashboard."""
|
||||
user = require_auth(request, db)
|
||||
if not user:
|
||||
return RedirectResponse(url="/login", status_code=302)
|
||||
|
||||
# Estadísticas
|
||||
now = datetime.utcnow()
|
||||
today_start = now.replace(hour=0, minute=0, second=0, microsecond=0)
|
||||
@@ -63,6 +75,7 @@ async def dashboard_home(request: Request, db: Session = Depends(get_db)):
|
||||
|
||||
return templates.TemplateResponse("index.html", {
|
||||
"request": request,
|
||||
"user": user.to_dict(),
|
||||
"stats": stats,
|
||||
"pending_posts": [p.to_dict() for p in pending_posts],
|
||||
"scheduled_posts": [p.to_dict() for p in scheduled_posts],
|
||||
@@ -73,46 +86,71 @@ async def dashboard_home(request: Request, db: Session = Depends(get_db)):
|
||||
@router.get("/posts", response_class=HTMLResponse)
|
||||
async def dashboard_posts(request: Request, db: Session = Depends(get_db)):
|
||||
"""Página de gestión de posts."""
|
||||
user = require_auth(request, db)
|
||||
if not user:
|
||||
return RedirectResponse(url="/login", status_code=302)
|
||||
|
||||
posts = db.query(Post).order_by(Post.created_at.desc()).limit(50).all()
|
||||
|
||||
return templates.TemplateResponse("posts.html", {
|
||||
"request": request,
|
||||
"user": user.to_dict(),
|
||||
"posts": [p.to_dict() for p in posts]
|
||||
})
|
||||
|
||||
|
||||
@router.get("/calendar", response_class=HTMLResponse)
|
||||
async def dashboard_calendar(request: Request):
|
||||
async def dashboard_calendar(request: Request, db: Session = Depends(get_db)):
|
||||
"""Página de calendario."""
|
||||
user = require_auth(request, db)
|
||||
if not user:
|
||||
return RedirectResponse(url="/login", status_code=302)
|
||||
|
||||
return templates.TemplateResponse("calendar.html", {
|
||||
"request": request
|
||||
"request": request,
|
||||
"user": user.to_dict()
|
||||
})
|
||||
|
||||
|
||||
@router.get("/interactions", response_class=HTMLResponse)
|
||||
async def dashboard_interactions(request: Request, db: Session = Depends(get_db)):
|
||||
"""Página de interacciones."""
|
||||
user = require_auth(request, db)
|
||||
if not user:
|
||||
return RedirectResponse(url="/login", status_code=302)
|
||||
|
||||
interactions = db.query(Interaction).filter(
|
||||
Interaction.is_archived == False
|
||||
).order_by(Interaction.interaction_at.desc()).limit(50).all()
|
||||
|
||||
return templates.TemplateResponse("interactions.html", {
|
||||
"request": request,
|
||||
"user": user.to_dict(),
|
||||
"interactions": [i.to_dict() for i in interactions]
|
||||
})
|
||||
|
||||
|
||||
@router.get("/products", response_class=HTMLResponse)
|
||||
async def dashboard_products(request: Request):
|
||||
async def dashboard_products(request: Request, db: Session = Depends(get_db)):
|
||||
"""Página de productos."""
|
||||
user = require_auth(request, db)
|
||||
if not user:
|
||||
return RedirectResponse(url="/login", status_code=302)
|
||||
|
||||
return templates.TemplateResponse("products.html", {
|
||||
"request": request
|
||||
"request": request,
|
||||
"user": user.to_dict()
|
||||
})
|
||||
|
||||
|
||||
@router.get("/services", response_class=HTMLResponse)
|
||||
async def dashboard_services(request: Request):
|
||||
async def dashboard_services(request: Request, db: Session = Depends(get_db)):
|
||||
"""Página de servicios."""
|
||||
user = require_auth(request, db)
|
||||
if not user:
|
||||
return RedirectResponse(url="/login", status_code=302)
|
||||
|
||||
return templates.TemplateResponse("services.html", {
|
||||
"request": request
|
||||
"request": request,
|
||||
"user": user.to_dict()
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user