diff --git a/src/providers/views.py b/src/providers/views.py index dc26011caf2ea55045a53a087df615b891b673b4..2985c37f3f4f49b9f78eed3d40df211d838c2c48 100644 --- a/src/providers/views.py +++ b/src/providers/views.py @@ -652,6 +652,8 @@ class GetAnalyticsEngineResult(APIView): engines = AnalyticsToken.objects.filter(id__in=payload["engines"]).all() engine_names = [engine.name for engine in engines] + + collection = lrs_db["results"] engine_results = collection.aggregate( @@ -762,42 +764,71 @@ class GetAnalyticsEngineResults(APIView): {"message": "Missing or invalid Authorization header."}, status=status.HTTP_400_BAD_REQUEST, ) - + try: token = auth_header.split("Basic ")[1] analytics_token = AnalyticsToken.objects.get(key=token) collection = lrs_db["results"] - # Pagination parameters - filters = request.data if request.method == "GET" else request.data - page = int(filters.get("page", filters.get("page", 1))) - page_size = int(filters.get("page_size", filters.get("page_size", 10))) + + # Extract filters from request + filters = request.query_params if request.method == "GET" else request.data + page = int(filters.get("page", 1)) + page_size = int(filters.get("page_size", 10)) skip = (page - 1) * page_size + + # Retrieve accessible engine names (default if no names provided) + allowed_names = set([analytics_token.name]) + allowed_names.update(analytics_token.can_access.values_list("name", flat=True)) + + # Extract requested names, if any + requested_names = filters.get("name") - # Filtering parameters - query = {"name": analytics_token.name} # Ensure it's a single value, not an array + # If no names are provided, use the default allowed names + if not requested_names: + requested_names = list(allowed_names) + elif isinstance(requested_names, str): + requested_names = [requested_names] # Convert single string to a list - # Apply filters dynamically + # Ensure all requested names are within allowed access + if any(name not in allowed_names for name in requested_names): + return Response( + { + "message": "Access denied to one or more requested engines.", + "allowed_engines": list(allowed_names) # Convert set to list for JSON serialization + }, + status=status.HTTP_403_FORBIDDEN, + ) + + # Filtering query for MongoDB + query = {"name": {"$in": requested_names}} + + # Apply additional filters dynamically for key, value in filters.items(): - if key in ["page", "page_size"]: - continue # Skip pagination params + if key in ["page", "page_size", "name"]: + continue # Skip pagination and name filters if key == "created_at": try: date_obj = datetime.strptime(value, "%Y-%m-%d") - query["created_at"] = {"$gte": datetime(date_obj.year, date_obj.month, date_obj.day, 0, 0, 0), - "$lt": datetime(date_obj.year, date_obj.month, date_obj.day, 23, 59, 59)} + query["created_at"] = { + "$gte": datetime(date_obj.year, date_obj.month, date_obj.day, 0, 0, 0), + "$lt": datetime(date_obj.year, date_obj.month, date_obj.day, 23, 59, 59) + } except ValueError: - return Response({"message": "Invalid date format. Use YYYY-MM-DD."}, status=status.HTTP_400_BAD_REQUEST) + return Response( + {"message": "Invalid date format. Use YYYY-MM-DD."}, + status=status.HTTP_400_BAD_REQUEST, + ) elif key.startswith("result."): query[key] = value # Filter inside the result JSON object else: query[key] = value - + total_results = collection.count_documents(query) total_pages = (total_results + page_size - 1) // page_size - + cursor = collection.find(query, sort=[("created_at", -1)]).skip(skip).limit(page_size) - + results_dict = {} for result in cursor: results_dict.setdefault(result.get("name", "unknown"), []).append( @@ -805,17 +836,20 @@ class GetAnalyticsEngineResults(APIView): "created_at": result.get("created_at", "unknown"), "result": result.get("result", {}), "context_id": result.get("context_id", "No context ID available"), - "description": result.get("description", "No description available") + "description": result.get("description", "No description available"), } ) - - return Response({ - "page": page, - "page_size": page_size, - "total_pages": total_pages, - "total_results": total_results, - "results": results_dict - }, status=status.HTTP_200_OK) + + return Response( + { + "page": page, + "page_size": page_size, + "total_pages": total_pages, + "total_results": total_results, + "results": results_dict, + }, + status=status.HTTP_200_OK, + ) except ObjectDoesNotExist: return Response( @@ -829,7 +863,6 @@ class GetAnalyticsEngineResults(APIView): status=status.HTTP_500_INTERNAL_SERVER_ERROR, ) - class CreateVisualizationToken(APIView): """ Creates visualization token for engines, engines_with_context and context_id. Requests need a valid application token in the header.