4040 TEXT ,
4141 BigInteger ,
4242 distinct ,
43+ inspect ,
4344)
4445
4546# # from DIRAC
@@ -188,6 +189,38 @@ class RequestDB:
188189 db holding requests
189190 """
190191
192+ @staticmethod
193+ def _get_column (table_name , column_name ):
194+ """Resolve supported ORM column attributes without evaluating input."""
195+
196+ models = {"Request" : Request , "Operation" : Operation }
197+ aliases = {"Status" : "_Status" }
198+
199+ model = models .get (table_name )
200+ if model is None :
201+ raise ValueError (f"Unknown table '{ table_name } '" )
202+
203+ resolved_name = aliases .get (column_name , column_name )
204+ if resolved_name not in inspect (model ).column_attrs :
205+ raise ValueError (f"Unknown { table_name } attribute '{ column_name } '" )
206+
207+ return getattr (model , resolved_name )
208+
209+ @classmethod
210+ def _apply_web_filter (cls , query , table_name , column_name , value ):
211+ column = cls ._get_column (table_name , column_name )
212+ if isinstance (value , list ):
213+ return query .filter (column .in_ (value ))
214+ return query .filter (column == value )
215+
216+ @classmethod
217+ def _get_order_expression (cls , table_name , column_name , direction ):
218+ column = cls ._get_column (table_name , column_name )
219+ normalized_direction = direction .lower ()
220+ if normalized_direction not in {"asc" , "desc" }:
221+ raise ValueError (f"Unknown sort direction '{ direction } '" )
222+ return getattr (column , normalized_direction )()
223+
191224 def __getDBConnectionInfo (self , fullname ):
192225 """Collect from the CS all the info needed to connect to the DB.
193226 This should be in a base class eventually
@@ -659,13 +692,12 @@ def getRequestSummaryWeb(self, selectDict, sortList, startItem, maxItems):
659692 elif key == "Status" :
660693 key = "_Status"
661694
662- if isinstance (value , list ):
663- summaryQuery = summaryQuery .filter (eval (f"{ tableName } .{ key } .in_({ value } )" ))
664- else :
665- summaryQuery = summaryQuery .filter (eval (f"{ tableName } .{ key } " ) == value )
695+ summaryQuery = self ._apply_web_filter (summaryQuery , tableName , key , value )
666696
667697 if sortList :
668- summaryQuery = summaryQuery .order_by (eval (f"Request.{ sortList [0 ][0 ]} .{ sortList [0 ][1 ].lower ()} ()" ))
698+ summaryQuery = summaryQuery .order_by (
699+ self ._get_order_expression ("Request" , sortList [0 ][0 ], sortList [0 ][1 ])
700+ )
669701
670702 try :
671703 requestLists = summaryQuery .all ()
@@ -699,6 +731,8 @@ def getRequestSummaryWeb(self, selectDict, sortList, startItem, maxItems):
699731 resultDict ["TotalRecords" ] = nRequests
700732
701733 return S_OK (resultDict )
734+ except ValueError as e :
735+ return S_ERROR (str (e ))
702736 #
703737 except Exception as e :
704738 self .log .exception ("getRequestSummaryWeb: unexpected exception" , lException = e )
@@ -718,17 +752,15 @@ def getRequestCountersWeb(self, groupingAttribute, selectDict):
718752
719753 session = self .DBSession ()
720754
721- if groupingAttribute == "Type" :
722- groupingAttribute = "Operation.Type"
723- elif groupingAttribute == "Status" :
724- groupingAttribute = "Request._Status"
725- else :
726- groupingAttribute = f"Request.{ groupingAttribute } "
727-
728755 try :
756+ if groupingAttribute == "Type" :
757+ groupingColumn = self ._get_column ("Operation" , "Type" )
758+ else :
759+ groupingColumn = self ._get_column ("Request" , groupingAttribute )
760+
729761 summaryQuery = session .query (
730- eval ( groupingAttribute ) , func .count (Request .RequestID ) # pylint: disable=not-callable
731- )
762+ groupingColumn , func .count (Request .RequestID )
763+ ) # pylint: disable=not-callable,no-member
732764
733765 for key , value in selectDict .items ():
734766 if key == "ToDate" :
@@ -743,12 +775,9 @@ def getRequestCountersWeb(self, groupingAttribute, selectDict):
743775 elif key == "Status" :
744776 key = "_Status"
745777
746- if isinstance (value , list ):
747- summaryQuery = summaryQuery .filter (eval (f"{ objectType } .{ key } .in_({ value } )" ))
748- else :
749- summaryQuery = summaryQuery .filter (eval (f"{ objectType } .{ key } " ) == value )
778+ summaryQuery = self ._apply_web_filter (summaryQuery , objectType , key , value )
750779
751- summaryQuery = summaryQuery .group_by (eval ( groupingAttribute ) )
780+ summaryQuery = summaryQuery .group_by (groupingColumn )
752781
753782 try :
754783 requestLists = summaryQuery .all ()
@@ -760,6 +789,8 @@ def getRequestCountersWeb(self, groupingAttribute, selectDict):
760789
761790 return S_OK (resultDict )
762791
792+ except ValueError as e :
793+ return S_ERROR (str (e ))
763794 except Exception as e :
764795 self .log .exception ("getRequestSummaryWeb: unexpected exception" , lException = e )
765796 return S_ERROR (f"getRequestSummaryWeb: unexpected exception : { e } " )
@@ -772,11 +803,11 @@ def getDistinctValues(self, tableName, columnName):
772803
773804 session = self .DBSession ()
774805 distinctValues = []
775- if columnName == "Status" :
776- columnName = "_Status"
777806 try :
778- result = session .query (distinct (eval ( f" { tableName } . { columnName } " ))).all ()
807+ result = session .query (distinct (self . _get_column ( tableName , columnName ))).all ()
779808 distinctValues = [dist [0 ] for dist in result ]
809+ except ValueError as e :
810+ return S_ERROR (str (e ))
780811 except NoResultFound :
781812 pass
782813 except Exception as e :
0 commit comments