diff --git a/modules/features/chatBot/service.py b/modules/features/chatBot/service.py index 9c2f7aa6..e4b63ff9 100644 --- a/modules/features/chatBot/service.py +++ b/modules/features/chatBot/service.py @@ -890,3 +890,52 @@ async def update_tool( logger.info(f"Successfully updated tool {tool_id}, fields: {updated_fields}") return updated_fields + + +async def get_tools_for_user(*, user_id: str, session: AsyncSession) -> List[dict]: + """Get all tools granted to a specific user. + + Args: + user_id: The user ID to get tools for. + session: The database session for querying. + + Returns: + List of tool dictionaries with all tool information. + """ + from modules.features.chatBot.database import Tool, UserToolMapping + + logger.info(f"Fetching tools for user {user_id}") + + # Query tools that are granted to the user + # Join UserToolMapping with Tool table + # Filter by user_id and active status + stmt = ( + select(Tool) + .join(UserToolMapping, Tool.id == UserToolMapping.tool_id) + .where( + UserToolMapping.user_id == user_id, + UserToolMapping.is_active == True, + Tool.is_active == True, + ) + .order_by(Tool.category, Tool.name) + ) + result = await session.execute(stmt) + tools = result.scalars().all() + + tool_list = [] + for tool in tools: + tool_dict = { + "id": str(tool.id), + "tool_id": tool.tool_id, + "name": tool.name, + "label": tool.label, + "category": tool.category, + "description": tool.description, + "is_active": tool.is_active, + "date_created": tool.date_created.timestamp(), + "date_updated": tool.date_updated.timestamp(), + } + tool_list.append(tool_dict) + + logger.info(f"Retrieved {len(tool_list)} tools for user {user_id}") + return tool_list diff --git a/modules/routes/routeChatbot.py b/modules/routes/routeChatbot.py index b9fbc092..65151017 100644 --- a/modules/routes/routeChatbot.py +++ b/modules/routes/routeChatbot.py @@ -534,3 +534,88 @@ async def update_tool( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=f"Failed to update tool: {type(e).__name__}: {str(e) or 'No error message provided'}", ) + + +@router.get("/tools/user/{user_id}", response_model=ToolListResponse) +@limiter.limit("30/minute") +async def get_tools_for_specific_user( + *, + request: Request, + user_id: str, + currentUser: User = Depends(getCurrentUser), + session: AsyncSession = Depends(get_async_db_session), +) -> ToolListResponse: + """ + Get all tools granted to a specific user. + Only accessible to system administrators. + """ + try: + # Check SYSADMIN permission + if currentUser.privilege != UserPrivilege.SYSADMIN: + raise HTTPException( + status_code=status.HTTP_403_FORBIDDEN, + detail="Only system administrators can view user tools", + ) + + # Get tools for the specified user + tools_data = await chat_service.get_tools_for_user( + user_id=user_id, session=session + ) + + # Convert to ToolInfo objects + tools = [ToolInfo(**tool) for tool in tools_data] + + logger.info( + f"User {currentUser.id} retrieved {len(tools)} tools for user {user_id}" + ) + + return ToolListResponse(tools=tools) + + except HTTPException: + raise + except Exception as e: + logger.error( + f"Error retrieving tools for user {user_id}: {type(e).__name__}: {str(e)}", + exc_info=True, + ) + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + detail=f"Failed to retrieve tools for user: {type(e).__name__}: {str(e) or 'No error message provided'}", + ) + + +@router.get("/tools/me", response_model=ToolListResponse) +@limiter.limit("30/minute") +async def get_my_tools( + *, + request: Request, + currentUser: User = Depends(getCurrentUser), + session: AsyncSession = Depends(get_async_db_session), +) -> ToolListResponse: + """ + Get all tools the current user has access to. + """ + try: + # Get tools for the current user + tools_data = await chat_service.get_tools_for_user( + user_id=currentUser.id, session=session + ) + + # Convert to ToolInfo objects + tools = [ToolInfo(**tool) for tool in tools_data] + + logger.info( + f"User {currentUser.id} retrieved {len(tools)} tools for themselves" + ) + + return ToolListResponse(tools=tools) + + except Exception as e: + logger.error( + f"Error retrieving tools for user {currentUser.id}: {type(e).__name__}: {str(e)}", + exc_info=True, + ) + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + detail=f"Failed to retrieve your tools: {type(e).__name__}: {str(e) or 'No error message provided'}", + )