""" Shared Companies Router Factory for ROA2WEB Applications Creates a FastAPI router for /api/companies endpoints that can be used by both the unified monolith backend. Usage: from shared.routes.companies import create_companies_router companies_router = create_companies_router(oracle_pool, cache_decorator=cached) app.include_router(companies_router, prefix="/api/companies") """ import logging from typing import Optional, Callable, List from fastapi import APIRouter, Depends, HTTPException, Request from auth.dependencies import get_current_user from auth.models import CurrentUser from models.company import Company, CompanyListResponse logger = logging.getLogger(__name__) def create_companies_router( oracle_pool, cache_decorator: Optional[Callable] = None, tags: Optional[List[str]] = None ) -> APIRouter: """ Factory function to create a companies router. Args: oracle_pool: The Oracle connection pool instance cache_decorator: Optional caching decorator (e.g., @cached) tags: OpenAPI tags for the router Returns: Configured FastAPI router for company endpoints """ router = APIRouter( redirect_slashes=False, tags=tags or ["companies"] ) # Helper function to get companies - can be cached async def _get_user_companies_data(username: str, server_id: Optional[str] = None) -> List[Company]: """ Get list of companies for a user from Oracle. Args: username: The username to get companies for server_id: The Oracle server ID (for multi-server mode) """ companies = [] async with oracle_pool.get_connection(server_id) as connection: with connection.cursor() as cursor: try: # Get user ID cursor.execute(""" SELECT ID_UTIL, UTILIZATOR FROM UTILIZATORI WHERE UPPER(UTILIZATOR) = :username """, {'username': username.upper()}) user_row = cursor.fetchone() if not user_row: logger.warning(f"User {username} not found in UTILIZATORI") return [] user_id = user_row[0] # Get companies for user (program 2 = data entry/reports) cursor.execute(""" SELECT A.ID_FIRMA, A.FIRMA, A.SCHEMA, A.COD_FISCAL FROM V_NOM_FIRME A WHERE A.ID_FIRMA IN ( SELECT ID_FIRMA FROM VDEF_UTIL_FIRME WHERE ID_PROGRAM = 2 AND ID_UTIL = :user_id ) ORDER BY A.FIRMA """, {'user_id': user_id}) for row in cursor.fetchall(): companies.append(Company( id_firma=row[0], name=row[1], schema_name=row[2], fiscal_code=row[3], is_active=True )) logger.info(f"Found {len(companies)} companies for user {username}") except Exception as e: logger.error(f"Error fetching companies: {e}") return companies # Apply cache decorator if provided # Include server_id in cache key for multi-server mode if cache_decorator: _get_user_companies_data = cache_decorator( cache_type='companies', key_params=['username', 'server_id'] )(_get_user_companies_data) @router.get("", response_model=CompanyListResponse) @router.get("/", response_model=CompanyListResponse) async def get_user_companies( request: Request, current_user: CurrentUser = Depends(get_current_user) ): """Get list of companies the user has access to.""" try: # Get server_id from request state (injected by auth middleware from JWT) server_id = getattr(request.state, 'server_id', None) companies = await _get_user_companies_data(current_user.username, server_id) return CompanyListResponse( companies=companies, total_count=len(companies) ) except Exception as e: logger.error(f"Error in get_user_companies: {e}") raise HTTPException(500, f"Eroare la obținerea listei de firme: {str(e)}") @router.get("/{company_id}", response_model=Company) async def get_company_details( company_id: str, request: Request, current_user: CurrentUser = Depends(get_current_user) ): """Get details of a specific company.""" # Validate access if company_id not in current_user.companies: raise HTTPException(403, f"Nu aveți acces la firma {company_id}") try: # Get server_id from request state (injected by auth middleware from JWT) server_id = getattr(request.state, 'server_id', None) async with oracle_pool.get_connection(server_id) as connection: with connection.cursor() as cursor: cursor.execute(""" SELECT ID_FIRMA, FIRMA, SCHEMA, COD_FISCAL FROM V_NOM_FIRME WHERE ID_FIRMA = :company_id """, {'company_id': int(company_id)}) row = cursor.fetchone() if not row: raise HTTPException(404, f"Firma {company_id} nu a fost găsită") return Company( id_firma=row[0], name=row[1], schema_name=row[2], fiscal_code=row[3] or "", is_active=True ) except HTTPException: raise except Exception as e: raise HTTPException(500, f"Eroare la obținerea detaliilor firmei: {str(e)}") @router.get("/{company_id}/validate") async def validate_company_access( company_id: str, current_user: CurrentUser = Depends(get_current_user) ): """Validate if user has access to a company.""" has_access = company_id in current_user.companies return { "company_id": company_id, "has_access": has_access, "user": current_user.username, "message": "Acces validat" if has_access else "Acces refuzat" } return router