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) # ✅ CORREGIDO: Type hint ): """ Crear nuevo sistema en el tenant del usuario actual. ✅ Implementa multi-tenancy: asigna automáticamente tenant_id del usuario. """ # ✅ CORREGIDO: Asignar tenant_id del usuario actual db_system = System( **system.model_dump(), tenant_id=current_user.tenant_id # ✅ Multi-tenancy automático ) 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. ✅ Implementa multi-tenancy: solo permite actualizar sistemas del propio tenant. """ 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). ✅ Implementa multi-tenancy: solo permite desactivar sistemas del propio tenant. """ 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