11from __future__ import annotations
22
3+ import datetime
4+
35from pydantic import BaseModel
46from sqlalchemy import select
57
8+ from diracx .core .exceptions import InvalidQueryError
69from diracx .db .sql .pilot_agents .schema import PilotAgents
710from diracx .db .sql .utils import BaseSQLDB
811
@@ -25,6 +28,12 @@ class LogMessage(BaseModel):
2528 vo : str
2629
2730
31+ class DateRange (BaseModel ):
32+ pilot_id : int | None = None
33+ min : str | None = None # expects a string in ISO 8601 ("%Y-%m-%dT%H:%M:%S.%f%z")
34+ max : str | None = None # expects a string in ISO 8601 ("%Y-%m-%dT%H:%M:%S.%f%z")
35+
36+
2837@router .post ("/" )
2938async def send_message (
3039 data : LogMessage ,
@@ -35,23 +44,27 @@ async def send_message(
3544 await check_permissions (action = ActionType .CREATE , pilot_db = pilot_logs_db )
3645
3746 pilot_id = 0 # need to get pilot id from pilot_stamp (via PilotAgentsDB)
47+ # also add a timestamp to be able to select and delete logs based on pilot creation dates, even if corresponding
48+ # pilots have been already deleted from PilotAgentsDB (so the logs can live longer than pilots).
49+ submission_time = datetime .datetime .fromtimestamp (0 , datetime .timezone .utc )
3850 piloAgentsDB = BaseSQLDB .available_implementations ("PilotAgentsDB" )[0 ]
3951 url = BaseSQLDB .available_urls ()["PilotAgentsDB" ]
4052 db = piloAgentsDB (url )
4153
4254 async with db .engine_context ():
4355 async with db :
44- stmt = select (PilotAgents .PilotID ).where (
56+ stmt = select (PilotAgents .PilotID , PilotAgents . SubmissionTime ).where (
4557 PilotAgents .PilotStamp == data .pilot_stamp
4658 )
47- pilot_id = (await db .conn .execute (stmt )).scalar_one ()
59+ pilot_id , submission_time = (await db .conn .execute (stmt )).one ()
4860
4961 docs = []
5062 for line in data .lines :
5163 docs .append (
5264 {
5365 "PilotStamp" : data .pilot_stamp ,
5466 "PilotID" : pilot_id ,
67+ "SubmissionTime" : submission_time ,
5568 "VO" : data .vo ,
5669 "LineNumber" : line .line_no ,
5770 "Message" : line .line ,
@@ -72,21 +85,35 @@ async def get_logs(
7285
7386 result = await db .search (
7487 ["Message" ],
75- [{"parameter" : "PilotID" , "operator" : "eq" } | { "value" : pilot_id }],
88+ [{"parameter" : "PilotID" , "operator" : "eq" , "value" : pilot_id }],
7689 [{"parameter" : "LineNumber" , "direction" : "asc" }],
7790 )
7891 if not result :
7992 return [f"No logs for pilot ID = { pilot_id } " ]
8093 return result
8194
8295
83- @router .delete ("/delete " )
84- async def delete_by_pilot_id (
85- pilot_id : int ,
96+ @router .delete ("/logs " )
97+ async def delete (
98+ data : DateRange ,
8699 db : PilotLogsDB ,
87100 check_permissions : CheckPilotLogsPolicyCallable ,
88- ):
89- logger . warning ( f"Deleting logs for pilot ID ' { pilot_id } '" )
101+ ) -> str :
102+ """Delete either logs for a specific PilotID or a creation date range."""
90103 await check_permissions (action = ActionType .DELETE , pilot_db = db )
91- await db .delete ([{"parameter" : "PilotID" , "operator" : "eq" } | {"value" : pilot_id }])
92- return f"Logs for pilot ID '{ pilot_id } ' successfully deleted"
104+ if data .pilot_id :
105+ await db .delete (
106+ [{"parameter" : "PilotID" , "operator" : "eq" , "value" : data .pilot_id }]
107+ )
108+ return f"Logs for pilot ID '{ data .pilot_id } ' successfully deleted"
109+ if data .min and not data .max :
110+ logger .warning (f"Deleting logs for pilots with submission data >='{ data .min } '" )
111+ await db .delete (
112+ [{"parameter" : "SubmissionTime" , "operator" : "gt" , "value" : data .min }]
113+ )
114+ return f"Logs for for pilots with submission data >='{ data .min } ' successfully deleted"
115+ if data .min and data .max :
116+ raise InvalidQueryError (
117+ "This query requires a range operater definition in DiracX"
118+ )
119+ return "no-op"
0 commit comments