1717"""
1818import json
1919import os
20+ import datetime
2021from collections import defaultdict
2122from pathlib import Path
2223from urllib .parse import urlparse
@@ -40,39 +41,72 @@ def list_calls():
4041 db = current_app .config ["db" ]
4142 logger = current_app .config ["logger" ]
4243
43- # ── required & validated params ──────────────────────────────
44- try :
45- rsid = int (request .args ["radio_system_id" ])
46- except (KeyError , ValueError ):
47- return _err ("radio_system_id (int) is required" , 400 )
44+ # ── params ──────────────────────────────
45+ rsid_arg = request .args .get ("radio_system_id" )
46+ rsid = None
47+ if rsid_arg :
48+ try :
49+ rsid = int (rsid_arg )
50+ except ValueError :
51+ pass
4852
4953 tone_type = request .args .get ("tone_type" )
5054 if tone_type and tone_type not in ALLOWED_TONE_TYPES :
5155 return _err ("invalid tone_type" , 400 )
5256
5357 trigger_only = request .args .get ("trigger_only" ) in ("1" , "true" , "yes" )
58+ trigger_id = request .args .get ("trigger_id" )
59+
60+ # Date filters
61+ date_from = request .args .get ("date_from" )
62+ date_to = request .args .get ("date_to" )
5463
5564 limit = max (1 , min (int (request .args .get ("limit" , 100 )), 500 ))
5665 offset = max (0 , int (request .args .get ("offset" , 0 )))
5766
5867 # ── SQL build ────────────────────────────────────────────────
5968 tone_filter = []
60- params = [rsid ]
69+ params = []
70+
71+ if rsid :
72+ tone_filter .append ("cr.radio_system_id = ?" )
73+ params .append (rsid )
74+
75+ # Filter by specific trigger
76+ if trigger_id :
77+ tone_filter .append ("""
78+ cr.call_id IN (
79+ SELECT DISTINCT ttm.call_id FROM tone_trigger_map ttm
80+ WHERE ttm.alert_trigger_id = ?
81+ )
82+ """ )
83+ params .append (int (trigger_id ))
6184
6285 if tone_type :
6386 tone_filter .append ("cte.tone_type = ?" )
6487 params .append (tone_type )
6588 if trigger_only :
6689 tone_filter .append ("cte.matches_trigger = 1" )
6790
68- where_extra = f"AND { ' AND ' .join (tone_filter )} " if tone_filter else ""
91+ # Date filters
92+ if date_from :
93+ tone_filter .append ("cr.start_epoch_s >= ?" )
94+ params .append (datetime .strptime (date_from , "%Y-%m-%d" ).timestamp ())
95+ if date_to :
96+ # Include the entire day
97+ tone_filter .append ("cr.start_epoch_s < ?" )
98+ params .append (datetime .strptime (date_to , "%Y-%m-%d" ).timestamp () + 86400 )
99+
100+ where_extra = f"WHERE { ' AND ' .join (tone_filter )} " if tone_filter else "WHERE 1=1"
69101
70102 sql = f"""
71103 SELECT cr.call_id,
72104 cr.start_epoch_s,
73105 cr.duration_s,
74106 cr.talkgroup,
75107 cr.file_path,
108+ cr.radio_system_id,
109+ rs.system_name,
76110 MAX(cte.matches_trigger) AS has_trigger,
77111 COUNT(cte.tone_event_id) AS tone_count,
78112 CASE
@@ -93,16 +127,14 @@ def list_calls():
93127 ELSE 0
94128 END
95129 ) AS has_address_geocoded,
96-
97- -- simple summary fields for the list
98130 MAX(ct.text_full) AS transcript_text,
99131 MAX(ct.address_geocoded_json) AS address_geocoded_json,
100132 MAX(ct.incident_category) AS incident_category
101-
133+
102134 FROM call_records cr
103135 JOIN call_tone_events cte USING(call_id)
104136 LEFT JOIN call_transcripts ct USING(call_id)
105- WHERE cr.radio_system_id = ?
137+ LEFT JOIN radio_systems rs ON cr.radio_system_id = rs.radio_system_id
106138 { where_extra }
107139 GROUP BY cr.call_id
108140 ORDER BY cr.start_epoch_s DESC
@@ -162,8 +194,9 @@ def list_calls():
162194 "has_transcript" : bool (r ["has_transcript" ]),
163195 "has_address_extracted" : bool (r ["has_address_extracted" ]),
164196 "has_address_geocoded" : bool (r ["has_address_geocoded" ]),
197+ "system_name" : r .get ("system_name" ) or "" ,
165198
166- # new “ simple” fields for the table
199+ # new " simple" fields for the table
167200 "transcript_simple" : transcript_simple ,
168201 "location_label" : location_label ,
169202 "location_lat" : location_lat ,
0 commit comments