- Criadas APIs para Health (métricas de saúde) * Registrar peso, altura, % gordura, medidas * Histórico completo de medições * Estatísticas e resumo - Criadas APIs para Tasks (tarefas) * Criar, editar e deletar tarefas * Filtros por status e data * Estatísticas detalhadas * Prioridades (baixa, média, alta) - Frontend implementado: * Página Health.tsx - registro de métricas * Página Tasks.tsx - gerenciamento de tarefas * Página Progress.tsx - visualização de progresso * Dashboard integrado com estatísticas reais - Schemas e modelos atualizados - Todas as funcionalidades testadas e operacionais
149 lines
4.8 KiB
Python
149 lines
4.8 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 datetime
|
|
|
|
from app.core.database import get_db
|
|
from app.core.security import decode_access_token, get_password_hash
|
|
from app.models.user import User
|
|
from app.schemas.admin import UserListResponse, UserUpdateRequest, PasswordChangeRequest
|
|
|
|
router = APIRouter(prefix="/admin", tags=["admin"])
|
|
security = HTTPBearer()
|
|
|
|
def get_current_superadmin(
|
|
credentials: HTTPAuthorizationCredentials = Depends(security),
|
|
db: Session = Depends(get_db)
|
|
) -> User:
|
|
"""Verifica se usuário é superadmin"""
|
|
token = credentials.credentials
|
|
payload = decode_access_token(token)
|
|
if not payload:
|
|
raise HTTPException(status_code=401, detail="Token inválido")
|
|
|
|
user_id = payload.get("sub")
|
|
user = db.query(User).filter(User.id == user_id).first()
|
|
|
|
if not user or not user.is_superadmin:
|
|
raise HTTPException(
|
|
status_code=403,
|
|
detail="Acesso negado. Apenas superadmin."
|
|
)
|
|
|
|
return user
|
|
|
|
@router.get("/users", response_model=List[UserListResponse])
|
|
async def list_all_users(
|
|
admin: User = Depends(get_current_superadmin),
|
|
db: Session = Depends(get_db)
|
|
):
|
|
"""Listar todos os usuários (apenas superadmin)"""
|
|
users = db.query(User).order_by(User.created_at.desc()).all()
|
|
return users
|
|
|
|
@router.get("/stats")
|
|
async def get_admin_stats(
|
|
admin: User = Depends(get_current_superadmin),
|
|
db: Session = Depends(get_db)
|
|
):
|
|
"""Estatísticas gerais do sistema"""
|
|
from sqlalchemy import func
|
|
from app.models.habit import Habit, HabitCompletion
|
|
|
|
total_users = db.query(func.count(User.id)).scalar()
|
|
active_users = db.query(func.count(User.id)).filter(User.is_active == True).scalar()
|
|
total_habits = db.query(func.count(Habit.id)).scalar()
|
|
total_completions = db.query(func.count(HabitCompletion.id)).scalar()
|
|
|
|
return {
|
|
"total_users": total_users,
|
|
"active_users": active_users,
|
|
"inactive_users": total_users - active_users,
|
|
"total_habits": total_habits,
|
|
"total_completions": total_completions
|
|
}
|
|
|
|
@router.patch("/users/{user_id}")
|
|
async def update_user(
|
|
user_id: str,
|
|
data: UserUpdateRequest,
|
|
admin: User = Depends(get_current_superadmin),
|
|
db: Session = Depends(get_db)
|
|
):
|
|
"""Atualizar dados de usuário"""
|
|
user = db.query(User).filter(User.id == user_id).first()
|
|
if not user:
|
|
raise HTTPException(status_code=404, detail="Usuário não encontrado")
|
|
|
|
# Atualizar campos
|
|
if data.email is not None:
|
|
# Verificar se email já existe
|
|
existing = db.query(User).filter(
|
|
User.email == data.email,
|
|
User.id != user_id
|
|
).first()
|
|
if existing:
|
|
raise HTTPException(status_code=400, detail="Email já em uso")
|
|
user.email = data.email
|
|
|
|
if data.username is not None:
|
|
# Verificar se username já existe
|
|
existing = db.query(User).filter(
|
|
User.username == data.username,
|
|
User.id != user_id
|
|
).first()
|
|
if existing:
|
|
raise HTTPException(status_code=400, detail="Username já em uso")
|
|
user.username = data.username
|
|
|
|
if data.full_name is not None:
|
|
user.full_name = data.full_name
|
|
|
|
if data.is_active is not None:
|
|
user.is_active = data.is_active
|
|
|
|
if data.is_verified is not None:
|
|
user.is_verified = data.is_verified
|
|
|
|
db.commit()
|
|
db.refresh(user)
|
|
|
|
return {"message": "Usuário atualizado", "user": user}
|
|
|
|
@router.delete("/users/{user_id}")
|
|
async def delete_user(
|
|
user_id: str,
|
|
admin: User = Depends(get_current_superadmin),
|
|
db: Session = Depends(get_db)
|
|
):
|
|
"""Deletar usuário (soft delete - apenas desativa)"""
|
|
user = db.query(User).filter(User.id == user_id).first()
|
|
if not user:
|
|
raise HTTPException(status_code=404, detail="Usuário não encontrado")
|
|
|
|
if user.is_superadmin:
|
|
raise HTTPException(status_code=403, detail="Não é possível deletar superadmin")
|
|
|
|
user.is_active = False
|
|
db.commit()
|
|
|
|
return {"message": "Usuário desativado com sucesso"}
|
|
|
|
@router.post("/users/{user_id}/reset-password")
|
|
async def reset_user_password(
|
|
user_id: str,
|
|
data: PasswordChangeRequest,
|
|
admin: User = Depends(get_current_superadmin),
|
|
db: Session = Depends(get_db)
|
|
):
|
|
"""Resetar senha de usuário"""
|
|
user = db.query(User).filter(User.id == user_id).first()
|
|
if not user:
|
|
raise HTTPException(status_code=404, detail="Usuário não encontrado")
|
|
|
|
user.password_hash = get_password_hash(data.new_password)
|
|
db.commit()
|
|
|
|
return {"message": "Senha alterada com sucesso"}
|