Files
ranking/backend/src/interface/api/routes.py
Frederico Castro f91651056a Refatoracao de qualidade de codigo
- Mover logica de routes.py para RankingMapper na camada de aplicacao
- Consolidar funcoes mesclar_periodos e anos_completos_periodos em periodo.py
- Extrair RankingCache para modulo separado em infrastructure/cache
- Substituir todos os print() por logging adequado
- Corrigir exception handlers genericos para tipos especificos
- Remover classe Atuacao e atributo atuacoes_raw nao utilizados
- Documentar status dos scripts utilitarios
2025-12-14 21:47:00 -03:00

173 lines
6.3 KiB
Python

from fastapi import APIRouter, Depends, HTTPException, Query, BackgroundTasks
from typing import Optional, List
from ...application.use_cases.obter_ranking import ObterRankingUseCase
from ...application.use_cases.obter_consultor import ObterConsultorUseCase
from ...application.mappers import RankingMapper
from ...infrastructure.repositories.consultor_repository_impl import ConsultorRepositoryImpl
from ..schemas.consultor_schema import (
RankingResponseSchema,
RankingDetalhadoResponseSchema,
ConsultorDetalhadoSchema,
ConsultorResumoSchema,
)
from ..schemas.ranking_schema import (
RankingPaginadoResponseSchema,
ConsultorRankingResumoSchema,
EstatisticasRankingSchema,
JobStatusSchema,
ProcessarRankingRequestSchema,
ProcessarRankingResponseSchema,
ConsultaNomeSchema,
)
from .dependencies import get_repository, get_ranking_repository, get_processar_job
from ...application.jobs.job_status import job_status
router = APIRouter(prefix="/api/v1", tags=["ranking"])
@router.get("/ranking", response_model=RankingResponseSchema)
async def obter_ranking(
limite: int = Query(default=100, ge=1, le=1000, description="Limite de consultores"),
offset: int = Query(default=0, ge=0, description="Offset para paginação"),
componente: Optional[str] = Query(
default=None, description="Filtrar por bloco (a, c, d)"
),
repository: ConsultorRepositoryImpl = Depends(get_repository),
):
use_case = ObterRankingUseCase(repository=repository)
consultores_dto = await use_case.executar(limite=limite, componente=componente)
total = await repository.contar_total()
consultores_schema = [
ConsultorResumoSchema(**vars(dto)) for dto in consultores_dto
]
return RankingResponseSchema(
total=total, limite=limite, offset=offset, consultores=consultores_schema
)
@router.get("/ranking/detalhado", response_model=RankingDetalhadoResponseSchema)
async def obter_ranking_detalhado(
limite: int = Query(default=100, ge=1, le=1000, description="Limite de consultores"),
componente: Optional[str] = Query(
default=None, description="Filtrar por bloco (a, c, d)"
),
repository: ConsultorRepositoryImpl = Depends(get_repository),
):
use_case = ObterRankingUseCase(repository=repository)
consultores_dto = await use_case.executar_detalhado(limite=limite, componente=componente)
total = await repository.contar_total()
consultores_schema = [
ConsultorDetalhadoSchema(**dto.to_dict()) for dto in consultores_dto
]
return RankingDetalhadoResponseSchema(total=total, limite=limite, consultores=consultores_schema)
@router.get("/consultor/{id_pessoa}", response_model=ConsultorDetalhadoSchema)
async def obter_consultor(
id_pessoa: int,
repository: ConsultorRepositoryImpl = Depends(get_repository),
):
use_case = ObterConsultorUseCase(repository=repository)
consultor = await use_case.executar(id_pessoa=id_pessoa)
if not consultor:
raise HTTPException(status_code=404, detail=f"Consultor {id_pessoa} não encontrado")
return consultor
@router.get("/health")
async def health_check():
return {"status": "ok", "message": "API Ranking CAPES funcionando"}
@router.get("/ranking/paginado", response_model=RankingPaginadoResponseSchema)
async def ranking_paginado(
page: int = Query(default=1, ge=1, description="Número da página"),
size: int = Query(default=50, ge=1, le=1000, description="Tamanho da página (máx 1000)"),
ativo: Optional[bool] = Query(default=None, description="Filtrar por status ativo"),
ranking_repo = Depends(get_ranking_repository),
):
total = ranking_repo.contar_total(filtro_ativo=ativo)
consultores = ranking_repo.buscar_paginado(page=page, size=size, filtro_ativo=ativo)
total_pages = (total + size - 1) // size
consultores_schema = [RankingMapper.consultor_ranking_to_schema(c) for c in consultores]
return RankingPaginadoResponseSchema(
total=total,
page=page,
size=size,
total_pages=total_pages,
consultores=consultores_schema
)
@router.get("/ranking/busca", response_model=List[ConsultaNomeSchema])
async def buscar_por_nome(
nome: str = Query(..., min_length=3, description="Nome (ou parte) para buscar"),
limit: int = Query(default=5, ge=1, le=20, description="Limite de resultados"),
ranking_repo = Depends(get_ranking_repository),
):
resultados = ranking_repo.buscar_por_nome(nome=nome, limit=limit)
return [
ConsultaNomeSchema(
id_pessoa=r["ID_PESSOA"],
nome=r["NOME"],
posicao=r["POSICAO"],
pontuacao_total=float(r["PONTUACAO_TOTAL"]),
)
for r in resultados
]
@router.get("/ranking/estatisticas", response_model=EstatisticasRankingSchema)
async def ranking_estatisticas(
ranking_repo = Depends(get_ranking_repository),
):
estatisticas = ranking_repo.obter_estatisticas()
distribuicao = ranking_repo.obter_distribuicao()
return EstatisticasRankingSchema(
total_consultores=estatisticas.get("total_consultores", 0),
total_ativos=estatisticas.get("total_ativos", 0),
total_inativos=estatisticas.get("total_inativos", 0),
ultima_atualizacao=estatisticas.get("ultima_atualizacao"),
pontuacao_media=estatisticas.get("pontuacao_media", 0),
pontuacao_maxima=estatisticas.get("pontuacao_maxima", 0),
pontuacao_minima=estatisticas.get("pontuacao_minima", 0),
media_blocos=estatisticas.get("media_componentes", {}),
distribuicao=distribuicao
)
@router.get("/ranking/status", response_model=JobStatusSchema)
async def status_processamento():
return JobStatusSchema(**job_status.to_dict())
@router.post("/ranking/processar", response_model=ProcessarRankingResponseSchema)
async def processar_ranking(
background_tasks: BackgroundTasks,
request: ProcessarRankingRequestSchema = ProcessarRankingRequestSchema(),
job = Depends(get_processar_job),
):
if job_status.is_running:
raise HTTPException(status_code=409, detail="Job já está em execução")
background_tasks.add_task(job.executar, limpar_antes=request.limpar_antes)
return ProcessarRankingResponseSchema(
sucesso=True,
mensagem="Processamento do ranking iniciado em background",
job_id="ranking_job"
)