feature/permisos-keycloak-correccion

This commit is contained in:
2026-05-04 13:22:18 -06:00
parent 376b99d1f9
commit 97bb5c23b6
15 changed files with 563 additions and 150 deletions

View File

@@ -18,7 +18,12 @@ from core.config import settings
from core.database import get_core_db
from core.s3_keys import company_certificate_key, company_logo_key
from core.storage_s3 import delete_object_if_exists, get_object_bytes, put_object_bytes
from core.security import get_current_user, get_tenant_from_token, validate_access_to_resource
from core.security import (
get_current_user,
get_tenant_from_token,
resolve_effective_tenant_id_from_user,
validate_access_to_resource,
)
from .....common.tenant_crud_routes import TenantCRUDRoutes
from .dto import CompanyCreateDTO, CompanyResponseDTO, CompanyUpdateDTO
from .models import Company
@@ -156,19 +161,23 @@ async def get_my_companies(
db: Session = Depends(get_core_db),
current_user: dict = Depends(get_current_user),
):
"""Get all companies that belong to the current user's tenant"""
tenant_id = current_user.get("tenant_id")
if not tenant_id:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail="Tenant ID not found in user data",
)
"""
Compañías accesibles: tenant del token/Hub (si existe) unión con membership en BD
(``user_company_roles``, ``user_company_permissions``, ``user_tenants``).
Un usuario solo con roles de app y sin ``tenant_id`` en /auth/me sigue pudiendo
listar sus compañías asignadas.
"""
user_id = current_user.get("sub") or current_user.get("id")
tenant_id = resolve_effective_tenant_id_from_user(current_user)
service = CompanyService(db)
companies = service.get_companies_by_tenant(tenant_id)
companies = service.get_companies_for_session_user(
keycloak_user_id=str(user_id) if user_id else None,
tenant_id_from_token=tenant_id,
)
return [
CompanyResponseDTO.model_validate(service.flatten_company_dto(company))
CompanyResponseDTO.model_validate(service.flatten_company_dto(company))
for company in companies
]

View File

@@ -4,7 +4,7 @@ Capa de servicio para lógica de negocio de empresa
import logging
from datetime import datetime
from typing import List, Optional, Tuple, Dict, Any
from typing import List, Optional, Tuple, Dict, Any, Set
from fastapi import HTTPException
from sqlalchemy.exc import IntegrityError
@@ -824,6 +824,36 @@ class CompanyService:
.all()
)
def get_companies_for_session_user(
self,
keycloak_user_id: Optional[str],
tenant_id_from_token: Optional[int],
) -> List[Company]:
"""
Compañías visibles para el usuario: unión de (a) todas las del tenant si el
token/Hub aporta tenant_id, y (b) compañías con membership RBAC o user_tenants.
Permite usuarios sin tenant_id en el JWT pero con roles asignados en la app.
"""
from core.security import collect_company_ids_from_app_membership
company_ids: Set[int] = set(
collect_company_ids_from_app_membership(
self.db, keycloak_user_id or ""
)
)
if tenant_id_from_token is not None:
for c in self.get_companies_by_tenant(int(tenant_id_from_token)):
company_ids.add(c.id)
if not company_ids:
return []
return (
self.db.query(Company)
.filter(Company.id.in_(company_ids), Company.deleted_at.is_(None))
.order_by(Company.name)
.all()
)
def exists_company(self, tenant_id: int) -> bool:
"""Check if a company exists for a tenant"""
return (