170 lines
5.5 KiB
Python
170 lines
5.5 KiB
Python
|
|
from fastapi import APIRouter, Depends, HTTPException, status
|
||
|
|
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
|
||
|
|
from sqlalchemy.orm import Session
|
||
|
|
from typing import List
|
||
|
|
from datetime import date
|
||
|
|
|
||
|
|
from app.core.database import get_db
|
||
|
|
from app.core.security import decode_access_token
|
||
|
|
from app.models.health import HealthMetric
|
||
|
|
from app.schemas.health import HealthMetricCreate, HealthMetricResponse, HealthMetricUpdate
|
||
|
|
|
||
|
|
router = APIRouter()
|
||
|
|
security = HTTPBearer()
|
||
|
|
|
||
|
|
def get_current_user_id(credentials: HTTPAuthorizationCredentials = Depends(security)) -> str:
|
||
|
|
"""Extrai user_id do token JWT"""
|
||
|
|
token = credentials.credentials
|
||
|
|
payload = decode_access_token(token)
|
||
|
|
if not payload:
|
||
|
|
raise HTTPException(status_code=401, detail="Token inválido")
|
||
|
|
return payload.get("sub")
|
||
|
|
|
||
|
|
@router.post("/", response_model=HealthMetricResponse, status_code=status.HTTP_201_CREATED)
|
||
|
|
async def create_health_metric(
|
||
|
|
metric_data: HealthMetricCreate,
|
||
|
|
user_id: str = Depends(get_current_user_id),
|
||
|
|
db: Session = Depends(get_db)
|
||
|
|
):
|
||
|
|
"""Criar nova métrica de saúde"""
|
||
|
|
new_metric = HealthMetric(
|
||
|
|
user_id=user_id,
|
||
|
|
measurement_date=metric_data.measurement_date,
|
||
|
|
measurement_time=metric_data.measurement_time,
|
||
|
|
weight=metric_data.weight,
|
||
|
|
height=metric_data.height,
|
||
|
|
body_fat_percentage=metric_data.body_fat_percentage,
|
||
|
|
muscle_mass=metric_data.muscle_mass,
|
||
|
|
waist=metric_data.waist,
|
||
|
|
chest=metric_data.chest,
|
||
|
|
hips=metric_data.hips,
|
||
|
|
notes=metric_data.notes
|
||
|
|
)
|
||
|
|
|
||
|
|
db.add(new_metric)
|
||
|
|
db.commit()
|
||
|
|
db.refresh(new_metric)
|
||
|
|
|
||
|
|
return new_metric
|
||
|
|
|
||
|
|
@router.get("/", response_model=List[HealthMetricResponse])
|
||
|
|
async def list_health_metrics(
|
||
|
|
user_id: str = Depends(get_current_user_id),
|
||
|
|
db: Session = Depends(get_db),
|
||
|
|
limit: int = 100
|
||
|
|
):
|
||
|
|
"""Listar todas as métricas de saúde do usuário"""
|
||
|
|
metrics = db.query(HealthMetric).filter(
|
||
|
|
HealthMetric.user_id == user_id
|
||
|
|
).order_by(HealthMetric.measurement_date.desc()).limit(limit).all()
|
||
|
|
|
||
|
|
return metrics
|
||
|
|
|
||
|
|
@router.get("/latest", response_model=HealthMetricResponse)
|
||
|
|
async def get_latest_metric(
|
||
|
|
user_id: str = Depends(get_current_user_id),
|
||
|
|
db: Session = Depends(get_db)
|
||
|
|
):
|
||
|
|
"""Obter última métrica registrada"""
|
||
|
|
metric = db.query(HealthMetric).filter(
|
||
|
|
HealthMetric.user_id == user_id
|
||
|
|
).order_by(HealthMetric.measurement_date.desc()).first()
|
||
|
|
|
||
|
|
if not metric:
|
||
|
|
raise HTTPException(status_code=404, detail="Nenhuma métrica encontrada")
|
||
|
|
|
||
|
|
return metric
|
||
|
|
|
||
|
|
@router.get("/{metric_id}", response_model=HealthMetricResponse)
|
||
|
|
async def get_health_metric(
|
||
|
|
metric_id: str,
|
||
|
|
user_id: str = Depends(get_current_user_id),
|
||
|
|
db: Session = Depends(get_db)
|
||
|
|
):
|
||
|
|
"""Obter métrica específica"""
|
||
|
|
metric = db.query(HealthMetric).filter(
|
||
|
|
HealthMetric.id == metric_id,
|
||
|
|
HealthMetric.user_id == user_id
|
||
|
|
).first()
|
||
|
|
|
||
|
|
if not metric:
|
||
|
|
raise HTTPException(status_code=404, detail="Métrica não encontrada")
|
||
|
|
|
||
|
|
return metric
|
||
|
|
|
||
|
|
@router.put("/{metric_id}", response_model=HealthMetricResponse)
|
||
|
|
async def update_health_metric(
|
||
|
|
metric_id: str,
|
||
|
|
metric_data: HealthMetricUpdate,
|
||
|
|
user_id: str = Depends(get_current_user_id),
|
||
|
|
db: Session = Depends(get_db)
|
||
|
|
):
|
||
|
|
"""Atualizar métrica de saúde"""
|
||
|
|
metric = db.query(HealthMetric).filter(
|
||
|
|
HealthMetric.id == metric_id,
|
||
|
|
HealthMetric.user_id == user_id
|
||
|
|
).first()
|
||
|
|
|
||
|
|
if not metric:
|
||
|
|
raise HTTPException(status_code=404, detail="Métrica não encontrada")
|
||
|
|
|
||
|
|
# Atualizar campos
|
||
|
|
update_data = metric_data.dict(exclude_unset=True)
|
||
|
|
for field, value in update_data.items():
|
||
|
|
setattr(metric, field, value)
|
||
|
|
|
||
|
|
db.commit()
|
||
|
|
db.refresh(metric)
|
||
|
|
|
||
|
|
return metric
|
||
|
|
|
||
|
|
@router.delete("/{metric_id}")
|
||
|
|
async def delete_health_metric(
|
||
|
|
metric_id: str,
|
||
|
|
user_id: str = Depends(get_current_user_id),
|
||
|
|
db: Session = Depends(get_db)
|
||
|
|
):
|
||
|
|
"""Deletar métrica de saúde"""
|
||
|
|
metric = db.query(HealthMetric).filter(
|
||
|
|
HealthMetric.id == metric_id,
|
||
|
|
HealthMetric.user_id == user_id
|
||
|
|
).first()
|
||
|
|
|
||
|
|
if not metric:
|
||
|
|
raise HTTPException(status_code=404, detail="Métrica não encontrada")
|
||
|
|
|
||
|
|
db.delete(metric)
|
||
|
|
db.commit()
|
||
|
|
|
||
|
|
return {"message": "Métrica deletada com sucesso"}
|
||
|
|
|
||
|
|
@router.get("/stats/summary")
|
||
|
|
async def get_health_stats(
|
||
|
|
user_id: str = Depends(get_current_user_id),
|
||
|
|
db: Session = Depends(get_db)
|
||
|
|
):
|
||
|
|
"""Estatísticas e resumo de saúde"""
|
||
|
|
latest = db.query(HealthMetric).filter(
|
||
|
|
HealthMetric.user_id == user_id
|
||
|
|
).order_by(HealthMetric.measurement_date.desc()).first()
|
||
|
|
|
||
|
|
# Pegar primeira e última medição para calcular diferença
|
||
|
|
first = db.query(HealthMetric).filter(
|
||
|
|
HealthMetric.user_id == user_id,
|
||
|
|
HealthMetric.weight.isnot(None)
|
||
|
|
).order_by(HealthMetric.measurement_date.asc()).first()
|
||
|
|
|
||
|
|
stats = {
|
||
|
|
"current_weight": float(latest.weight) if latest and latest.weight else None,
|
||
|
|
"current_height": float(latest.height) if latest and latest.height else None,
|
||
|
|
"current_body_fat": float(latest.body_fat_percentage) if latest and latest.body_fat_percentage else None,
|
||
|
|
"weight_change": None,
|
||
|
|
"total_measurements": db.query(HealthMetric).filter(HealthMetric.user_id == user_id).count()
|
||
|
|
}
|
||
|
|
|
||
|
|
if latest and first and latest.weight and first.weight:
|
||
|
|
stats["weight_change"] = float(latest.weight - first.weight)
|
||
|
|
|
||
|
|
return stats
|
||
|
|
|