feat(fase3): add Queue and QuickReply API routes
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -2,7 +2,7 @@ from fastapi import FastAPI
|
|||||||
from fastapi.middleware.cors import CORSMiddleware
|
from fastapi.middleware.cors import CORSMiddleware
|
||||||
from app.core.config import get_settings
|
from app.core.config import get_settings
|
||||||
from app.core.database import engine, Base
|
from app.core.database import engine, Base
|
||||||
from app.routers import auth, whatsapp, flows, supervisor
|
from app.routers import auth, whatsapp, flows, queues, supervisor
|
||||||
|
|
||||||
settings = get_settings()
|
settings = get_settings()
|
||||||
|
|
||||||
@@ -29,6 +29,7 @@ app.add_middleware(
|
|||||||
app.include_router(auth.router)
|
app.include_router(auth.router)
|
||||||
app.include_router(whatsapp.router)
|
app.include_router(whatsapp.router)
|
||||||
app.include_router(flows.router)
|
app.include_router(flows.router)
|
||||||
|
app.include_router(queues.router)
|
||||||
app.include_router(supervisor.router)
|
app.include_router(supervisor.router)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
243
services/api-gateway/app/routers/queues.py
Normal file
243
services/api-gateway/app/routers/queues.py
Normal file
@@ -0,0 +1,243 @@
|
|||||||
|
from fastapi import APIRouter, Depends, HTTPException
|
||||||
|
from sqlalchemy.orm import Session
|
||||||
|
from typing import List
|
||||||
|
from uuid import UUID
|
||||||
|
from app.core.database import get_db
|
||||||
|
from app.core.security import get_current_user
|
||||||
|
from app.models.user import User, UserRole
|
||||||
|
from app.models.queue import Queue, QueueAgent
|
||||||
|
from app.models.quick_reply import QuickReply
|
||||||
|
from app.schemas.queue import (
|
||||||
|
QueueCreate, QueueUpdate, QueueResponse, QueueDetailResponse,
|
||||||
|
QueueAgentAdd, QueueAgentResponse,
|
||||||
|
QuickReplyCreate, QuickReplyUpdate, QuickReplyResponse
|
||||||
|
)
|
||||||
|
|
||||||
|
router = APIRouter(prefix="/api/queues", tags=["queues"])
|
||||||
|
|
||||||
|
|
||||||
|
def require_admin(current_user: User = Depends(get_current_user)) -> User:
|
||||||
|
if current_user.role != UserRole.ADMIN:
|
||||||
|
raise HTTPException(status_code=403, detail="Admin required")
|
||||||
|
return current_user
|
||||||
|
|
||||||
|
|
||||||
|
def require_supervisor(current_user: User = Depends(get_current_user)) -> User:
|
||||||
|
if current_user.role not in [UserRole.ADMIN, UserRole.SUPERVISOR]:
|
||||||
|
raise HTTPException(status_code=403, detail="Supervisor or Admin required")
|
||||||
|
return current_user
|
||||||
|
|
||||||
|
|
||||||
|
@router.post("", response_model=QueueResponse)
|
||||||
|
def create_queue(
|
||||||
|
request: QueueCreate,
|
||||||
|
db: Session = Depends(get_db),
|
||||||
|
current_user: User = Depends(require_admin),
|
||||||
|
) -> Queue:
|
||||||
|
queue = Queue(**request.model_dump())
|
||||||
|
db.add(queue)
|
||||||
|
db.commit()
|
||||||
|
db.refresh(queue)
|
||||||
|
return queue
|
||||||
|
|
||||||
|
|
||||||
|
@router.get("", response_model=List[QueueResponse])
|
||||||
|
def list_queues(
|
||||||
|
db: Session = Depends(get_db),
|
||||||
|
current_user: User = Depends(get_current_user),
|
||||||
|
) -> List[QueueResponse]:
|
||||||
|
queues = db.query(Queue).filter(Queue.is_active == True).all()
|
||||||
|
result = []
|
||||||
|
for q in queues:
|
||||||
|
q_dict = QueueResponse.model_validate(q).model_dump()
|
||||||
|
q_dict["agent_count"] = len(q.agents)
|
||||||
|
result.append(QueueResponse(**q_dict))
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
@router.get("/{queue_id}", response_model=QueueDetailResponse)
|
||||||
|
def get_queue(
|
||||||
|
queue_id: UUID,
|
||||||
|
db: Session = Depends(get_db),
|
||||||
|
current_user: User = Depends(get_current_user),
|
||||||
|
) -> QueueDetailResponse:
|
||||||
|
queue = db.query(Queue).filter(Queue.id == queue_id).first()
|
||||||
|
if not queue:
|
||||||
|
raise HTTPException(status_code=404, detail="Queue not found")
|
||||||
|
|
||||||
|
agents_data = []
|
||||||
|
for qa in queue.agents:
|
||||||
|
agents_data.append(QueueAgentResponse(
|
||||||
|
id=qa.id,
|
||||||
|
user_id=qa.user_id,
|
||||||
|
user_name=qa.user.name if qa.user else None,
|
||||||
|
user_email=qa.user.email if qa.user else None,
|
||||||
|
is_supervisor=qa.is_supervisor,
|
||||||
|
skills=qa.skills or [],
|
||||||
|
created_at=qa.created_at,
|
||||||
|
))
|
||||||
|
|
||||||
|
return QueueDetailResponse(
|
||||||
|
**QueueResponse.model_validate(queue).model_dump(),
|
||||||
|
agents=agents_data,
|
||||||
|
agent_count=len(agents_data),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@router.put("/{queue_id}", response_model=QueueResponse)
|
||||||
|
def update_queue(
|
||||||
|
queue_id: UUID,
|
||||||
|
request: QueueUpdate,
|
||||||
|
db: Session = Depends(get_db),
|
||||||
|
current_user: User = Depends(require_admin),
|
||||||
|
) -> Queue:
|
||||||
|
queue = db.query(Queue).filter(Queue.id == queue_id).first()
|
||||||
|
if not queue:
|
||||||
|
raise HTTPException(status_code=404, detail="Queue not found")
|
||||||
|
|
||||||
|
for key, value in request.model_dump(exclude_unset=True).items():
|
||||||
|
setattr(queue, key, value)
|
||||||
|
|
||||||
|
db.commit()
|
||||||
|
db.refresh(queue)
|
||||||
|
return queue
|
||||||
|
|
||||||
|
|
||||||
|
@router.delete("/{queue_id}")
|
||||||
|
def delete_queue(
|
||||||
|
queue_id: UUID,
|
||||||
|
db: Session = Depends(get_db),
|
||||||
|
current_user: User = Depends(require_admin),
|
||||||
|
) -> dict:
|
||||||
|
queue = db.query(Queue).filter(Queue.id == queue_id).first()
|
||||||
|
if not queue:
|
||||||
|
raise HTTPException(status_code=404, detail="Queue not found")
|
||||||
|
|
||||||
|
queue.is_active = False
|
||||||
|
db.commit()
|
||||||
|
return {"success": True}
|
||||||
|
|
||||||
|
|
||||||
|
@router.post("/{queue_id}/agents", response_model=QueueAgentResponse)
|
||||||
|
def add_agent_to_queue(
|
||||||
|
queue_id: UUID,
|
||||||
|
request: QueueAgentAdd,
|
||||||
|
db: Session = Depends(get_db),
|
||||||
|
current_user: User = Depends(require_admin),
|
||||||
|
) -> QueueAgentResponse:
|
||||||
|
queue = db.query(Queue).filter(Queue.id == queue_id).first()
|
||||||
|
if not queue:
|
||||||
|
raise HTTPException(status_code=404, detail="Queue not found")
|
||||||
|
|
||||||
|
existing = db.query(QueueAgent).filter(
|
||||||
|
QueueAgent.queue_id == queue_id,
|
||||||
|
QueueAgent.user_id == request.user_id
|
||||||
|
).first()
|
||||||
|
if existing:
|
||||||
|
raise HTTPException(status_code=400, detail="Agent already in queue")
|
||||||
|
|
||||||
|
qa = QueueAgent(
|
||||||
|
queue_id=queue_id,
|
||||||
|
user_id=request.user_id,
|
||||||
|
is_supervisor=request.is_supervisor,
|
||||||
|
skills=request.skills,
|
||||||
|
)
|
||||||
|
db.add(qa)
|
||||||
|
db.commit()
|
||||||
|
db.refresh(qa)
|
||||||
|
|
||||||
|
return QueueAgentResponse(
|
||||||
|
id=qa.id,
|
||||||
|
user_id=qa.user_id,
|
||||||
|
user_name=qa.user.name if qa.user else None,
|
||||||
|
user_email=qa.user.email if qa.user else None,
|
||||||
|
is_supervisor=qa.is_supervisor,
|
||||||
|
skills=qa.skills or [],
|
||||||
|
created_at=qa.created_at,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@router.delete("/{queue_id}/agents/{user_id}")
|
||||||
|
def remove_agent_from_queue(
|
||||||
|
queue_id: UUID,
|
||||||
|
user_id: UUID,
|
||||||
|
db: Session = Depends(get_db),
|
||||||
|
current_user: User = Depends(require_admin),
|
||||||
|
) -> dict:
|
||||||
|
qa = db.query(QueueAgent).filter(
|
||||||
|
QueueAgent.queue_id == queue_id,
|
||||||
|
QueueAgent.user_id == user_id
|
||||||
|
).first()
|
||||||
|
if not qa:
|
||||||
|
raise HTTPException(status_code=404, detail="Agent not in queue")
|
||||||
|
|
||||||
|
db.delete(qa)
|
||||||
|
db.commit()
|
||||||
|
return {"success": True}
|
||||||
|
|
||||||
|
|
||||||
|
@router.get("/quick-replies", response_model=List[QuickReplyResponse])
|
||||||
|
def list_quick_replies(
|
||||||
|
queue_id: UUID = None,
|
||||||
|
db: Session = Depends(get_db),
|
||||||
|
current_user: User = Depends(get_current_user),
|
||||||
|
) -> List[QuickReply]:
|
||||||
|
query = db.query(QuickReply)
|
||||||
|
if queue_id:
|
||||||
|
query = query.filter(
|
||||||
|
(QuickReply.queue_id == queue_id) | (QuickReply.queue_id == None)
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
query = query.filter(QuickReply.queue_id == None)
|
||||||
|
|
||||||
|
return query.all()
|
||||||
|
|
||||||
|
|
||||||
|
@router.post("/quick-replies", response_model=QuickReplyResponse)
|
||||||
|
def create_quick_reply(
|
||||||
|
request: QuickReplyCreate,
|
||||||
|
db: Session = Depends(get_db),
|
||||||
|
current_user: User = Depends(require_supervisor),
|
||||||
|
) -> QuickReply:
|
||||||
|
qr = QuickReply(
|
||||||
|
**request.model_dump(),
|
||||||
|
created_by=current_user.id,
|
||||||
|
)
|
||||||
|
db.add(qr)
|
||||||
|
db.commit()
|
||||||
|
db.refresh(qr)
|
||||||
|
return qr
|
||||||
|
|
||||||
|
|
||||||
|
@router.put("/quick-replies/{reply_id}", response_model=QuickReplyResponse)
|
||||||
|
def update_quick_reply(
|
||||||
|
reply_id: UUID,
|
||||||
|
request: QuickReplyUpdate,
|
||||||
|
db: Session = Depends(get_db),
|
||||||
|
current_user: User = Depends(require_supervisor),
|
||||||
|
) -> QuickReply:
|
||||||
|
qr = db.query(QuickReply).filter(QuickReply.id == reply_id).first()
|
||||||
|
if not qr:
|
||||||
|
raise HTTPException(status_code=404, detail="Quick reply not found")
|
||||||
|
|
||||||
|
for key, value in request.model_dump(exclude_unset=True).items():
|
||||||
|
setattr(qr, key, value)
|
||||||
|
|
||||||
|
db.commit()
|
||||||
|
db.refresh(qr)
|
||||||
|
return qr
|
||||||
|
|
||||||
|
|
||||||
|
@router.delete("/quick-replies/{reply_id}")
|
||||||
|
def delete_quick_reply(
|
||||||
|
reply_id: UUID,
|
||||||
|
db: Session = Depends(get_db),
|
||||||
|
current_user: User = Depends(require_supervisor),
|
||||||
|
) -> dict:
|
||||||
|
qr = db.query(QuickReply).filter(QuickReply.id == reply_id).first()
|
||||||
|
if not qr:
|
||||||
|
raise HTTPException(status_code=404, detail="Quick reply not found")
|
||||||
|
|
||||||
|
db.delete(qr)
|
||||||
|
db.commit()
|
||||||
|
return {"success": True}
|
||||||
Reference in New Issue
Block a user