from fastapi import APIRouter, Depends, HTTPException, status from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy import select from pydantic import BaseModel, ConfigDict from typing import List, Optional from datetime import datetime import uuid from app.core.database import get_db from app.models.system import System from app.models.user import User from app.api import deps router = APIRouter() # =================================== # PYDANTIC SCHEMAS # =================================== class SystemCreate(BaseModel): """Schema para crear sistema - NO incluye tenant_id (se asigna automáticamente)""" name: str description: Optional[str] = None class SystemUpdate(BaseModel): """Schema para actualizar sistema""" name: Optional[str] = None description: Optional[str] = None is_active: Optional[bool] = None class SystemResponse(BaseModel): """Schema de respuesta - incluye todos los campos""" id: uuid.UUID tenant_id: uuid.UUID # ✅ AÑADIDO name: str description: Optional[str] = None is_active: bool created_at: datetime # ✅ AÑADIDO updated_at: datetime # ✅ AÑADIDO model_config = ConfigDict(from_attributes=True) # =================================== # ENDPOINTS # =================================== @router.get("/", response_model=List[SystemResponse]) async def read_systems( skip: int = 0, limit: int = 100, db: AsyncSession = Depends(get_db), current_user: User = Depends(deps.get_current_user) # ✅ CORREGIDO: Type hint + no solo superuser ): """ Listar sistemas del tenant del usuario actual. ✅ Implementa multi-tenancy: solo muestra sistemas del tenant del usuario. """ # ✅ CORREGIDO: Filtrar por tenant_id query = select(System).where( System.tenant_id == current_user.tenant_id ).offset(skip).limit(limit) result = await db.execute(query) return result.scalars().all() @router.post("/", response_model=SystemResponse, status_code=status.HTTP_201_CREATED) async def create_system( system: SystemCreate, db: AsyncSession = Depends(get_db), current_user: User = Depends(deps.get_current_user) ): """ Crear nuevo sistema en el tenant del usuario actual. **Permisos**: Solo ADMIN y SUPPORT_MANAGER pueden crear sistemas. ✅ Implementa multi-tenancy: asigna automáticamente tenant_id del usuario. """ # Verificar permisos if current_user.role not in ["ADMIN", "SUPPORT_MANAGER"]: raise HTTPException( status_code=status.HTTP_403_FORBIDDEN, detail="No tienes permisos para crear sistemas" ) # Asignar tenant_id del usuario actual db_system = System( **system.model_dump(), tenant_id=current_user.tenant_id ) db.add(db_system) await db.commit() await db.refresh(db_system) return db_system @router.get("/{system_id}", response_model=SystemResponse) async def read_system( system_id: uuid.UUID, db: AsyncSession = Depends(get_db), current_user: User = Depends(deps.get_current_user) ): """ Obtener un sistema específico del tenant. ✅ Implementa multi-tenancy: solo permite acceso a sistemas del propio tenant. """ query = select(System).where( System.id == system_id, System.tenant_id == current_user.tenant_id # ✅ Seguridad multi-tenant ) result = await db.execute(query) system = result.scalar_one_or_none() if not system: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="System not found" ) return system @router.put("/{system_id}", response_model=SystemResponse) async def update_system( system_id: uuid.UUID, system_update: SystemUpdate, db: AsyncSession = Depends(get_db), current_user: User = Depends(deps.get_current_user) ): """ Actualizar sistema del tenant. **Permisos**: Solo ADMIN y SUPPORT_MANAGER pueden actualizar sistemas. ✅ Implementa multi-tenancy: solo permite actualizar sistemas del propio tenant. """ # Verificar permisos if current_user.role not in ["ADMIN", "SUPPORT_MANAGER"]: raise HTTPException( status_code=status.HTTP_403_FORBIDDEN, detail="No tienes permisos para actualizar sistemas" ) query = select(System).where( System.id == system_id, System.tenant_id == current_user.tenant_id ) result = await db.execute(query) db_system = result.scalar_one_or_none() if not db_system: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="System not found" ) # Actualizar campos update_data = system_update.model_dump(exclude_unset=True) for field, value in update_data.items(): setattr(db_system, field, value) await db.commit() await db.refresh(db_system) return db_system @router.delete("/{system_id}", status_code=status.HTTP_204_NO_CONTENT) async def delete_system( system_id: uuid.UUID, db: AsyncSession = Depends(get_db), current_user: User = Depends(deps.get_current_user) ): """ Desactivar sistema del tenant (soft delete). **Permisos**: Solo ADMIN y SUPPORT_MANAGER pueden desactivar sistemas. ✅ Implementa multi-tenancy: solo permite desactivar sistemas del propio tenant. """ # Verificar permisos if current_user.role not in ["ADMIN", "SUPPORT_MANAGER"]: raise HTTPException( status_code=status.HTTP_403_FORBIDDEN, detail="No tienes permisos para desactivar sistemas" ) query = select(System).where( System.id == system_id, System.tenant_id == current_user.tenant_id ) result = await db.execute(query) db_system = result.scalar_one_or_none() if not db_system: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="System not found" ) # Soft delete db_system.is_active = False await db.commit() return None