@@ -43,6 +43,21 @@ pub struct CompleteThread {
4343#[ derive( Debug , Deserialize ) ]
4444pub struct TicketQuery {
4545 pub id : Option < String > ,
46+ pub page : Option < i64 > ,
47+ pub page_size : Option < i64 > ,
48+ pub status : Option < i64 > ,
49+ pub category_id : Option < String > ,
50+ pub sort_by : Option < String > ,
51+ pub sort_order : Option < String > ,
52+ }
53+
54+ #[ derive( Debug , Serialize ) ]
55+ pub struct PaginatedThreadsResponse {
56+ pub threads : Vec < CompleteThread > ,
57+ pub total : i64 ,
58+ pub page : i64 ,
59+ pub page_size : i64 ,
60+ pub total_pages : i64 ,
4661}
4762
4863pub async fn handle_tickets_bot (
@@ -177,27 +192,90 @@ pub async fn handle_tickets_bot(
177192 return ( StatusCode :: OK , Json ( serde_json:: json!( complete) ) ) ;
178193 }
179194
180- let threads_query = match sqlx:: query!(
195+ let page = params. page . unwrap_or ( 1 ) . max ( 1 ) ;
196+ let page_size = params. page_size . unwrap_or ( 50 ) . min ( 200 ) . max ( 1 ) ;
197+ let offset = ( page - 1 ) * page_size;
198+
199+ let status_filter = params. status . unwrap_or ( 0 ) ;
200+
201+ let mut where_conditions = vec ! [ format!( "status = {}" , status_filter) ] ;
202+
203+ if let Some ( ref cat_id) = params. category_id {
204+ where_conditions. push ( format ! ( "category_id = '{}'" , cat_id. replace( "'" , "''" ) ) ) ;
205+ }
206+
207+ let where_clause = where_conditions. join ( " AND " ) ;
208+
209+ let sort_column = match params. sort_by . as_deref ( ) {
210+ Some ( "user_name" ) => "user_name" ,
211+ Some ( "closed_at" ) => "closed_at" ,
212+ Some ( "created_at" ) => "created_at" ,
213+ _ => "created_at" ,
214+ } ;
215+
216+ let sort_order = match params. sort_order . as_deref ( ) {
217+ Some ( "asc" ) => "ASC" ,
218+ _ => "DESC" ,
219+ } ;
220+
221+ let count_query = format ! ( "SELECT COUNT(*) as count FROM threads WHERE {}" , where_clause) ;
222+ let total: i64 = match sqlx:: query_scalar ( & count_query)
223+ . fetch_one ( & db_pool)
224+ . await
225+ {
226+ Ok ( count) => count,
227+ Err ( err) => {
228+ eprintln ! ( "Erreur SQL count: {:?}" , err) ;
229+ return (
230+ StatusCode :: INTERNAL_SERVER_ERROR ,
231+ Json ( serde_json:: json!( {
232+ "error" : "Failed to count threads"
233+ } ) ) ,
234+ ) ;
235+ }
236+ } ;
237+
238+ let total_pages = ( total as f64 / page_size as f64 ) . ceil ( ) as i64 ;
239+
240+ let query_str = format ! (
181241 r#"
182242 SELECT
183243 id,
184244 user_id,
185245 user_name,
186246 channel_id,
187- strftime('%s', created_at) as " created_at: Option<String>" ,
247+ strftime('%s', created_at) as created_at,
188248 next_message_number as new_message_number,
189249 status,
190250 user_left,
191- strftime('%s', closed_at) as " closed_at: Option<String>" ,
251+ strftime('%s', closed_at) as closed_at,
192252 closed_by,
193253 category_id,
194254 category_name,
195255 required_permissions
196256 FROM threads
197- WHERE status = 0
198- ORDER BY closed_at DESC
199- "#
200- )
257+ WHERE {}
258+ ORDER BY {} {}
259+ LIMIT {} OFFSET {}
260+ "# ,
261+ where_clause, sort_column, sort_order, page_size, offset
262+ ) ;
263+
264+ let threads_query = match sqlx:: query_as :: < _ , (
265+ String ,
266+ i64 ,
267+ String ,
268+ String ,
269+ Option < String > ,
270+ Option < i64 > ,
271+ i64 ,
272+ bool ,
273+ Option < String > ,
274+ Option < String > ,
275+ Option < String > ,
276+ Option < String > ,
277+ Option < String > ,
278+ ) > ( & query_str)
201279 . fetch_all ( & db_pool)
202280 . await
203281 {
@@ -215,72 +293,99 @@ pub async fn handle_tickets_bot(
215293
216294 let mut threads: Vec < CompleteThread > = Vec :: new ( ) ;
217295
218- for thread in threads_query {
219- let messages_query = match sqlx:: query!(
220- r#"
221- SELECT
222- id,
223- thread_id,
224- user_id,
225- user_name,
226- is_anonymous,
227- dm_message_id,
228- inbox_message_id,
229- message_number,
230- created_at as "created_at: String",
231- content
232- FROM thread_messages
233- WHERE thread_id = ?
234- ORDER BY created_at ASC
235- "# ,
236- thread. id
237- )
238- . fetch_all ( & db_pool)
239- . await
240- {
241- Ok ( rows) => rows,
242- Err ( err) => {
243- eprintln ! ( "Erreur SQL messages pour {}: {:?}" , thread. id, err) ;
244- Vec :: new ( )
245- }
246- } ;
296+ let thread_ids: Vec < String > = threads_query. iter ( ) . map ( |t| t. 0 . clone ( ) ) . collect ( ) ;
247297
248- let messages: Vec < ThreadMessage > = messages_query
249- . into_iter ( )
250- . map ( |m| ThreadMessage {
251- id : m. id ,
252- thread_id : m. thread_id ,
253- user_id : m. user_id ,
254- user_name : m. user_name ,
255- is_anonymous : m. is_anonymous ,
256- dm_message_id : m. dm_message_id ,
257- inbox_message_id : m. inbox_message_id ,
258- message_number : m. message_number ,
259- created_at : m. created_at ,
260- content : m. content ,
261- } )
262- . collect ( ) ;
298+ let placeholders = thread_ids. iter ( ) . map ( |_| "?" ) . collect :: < Vec < _ > > ( ) . join ( "," ) ;
299+ let messages_query_str = format ! (
300+ r#"
301+ SELECT
302+ id,
303+ thread_id,
304+ user_id,
305+ user_name,
306+ is_anonymous,
307+ dm_message_id,
308+ inbox_message_id,
309+ message_number,
310+ created_at,
311+ content
312+ FROM thread_messages
313+ WHERE thread_id IN ({})
314+ ORDER BY thread_id, created_at ASC
315+ "# ,
316+ placeholders
317+ ) ;
318+
319+ let mut messages_query = sqlx:: query_as :: < _ , (
320+ i64 ,
321+ String ,
322+ i64 ,
323+ String ,
324+ bool ,
325+ Option < String > ,
326+ Option < String > ,
327+ Option < i64 > ,
328+ String ,
329+ String ,
330+ ) > ( & messages_query_str) ;
331+
332+ for thread_id in & thread_ids {
333+ messages_query = messages_query. bind ( thread_id) ;
334+ }
335+
336+ let all_messages = messages_query. fetch_all ( & db_pool) . await . unwrap_or_else ( |err| {
337+ eprintln ! ( "Erreur SQL messages batch: {:?}" , err) ;
338+ Vec :: new ( )
339+ } ) ;
340+
341+ let mut messages_by_thread: std:: collections:: HashMap < String , Vec < ThreadMessage > > =
342+ std:: collections:: HashMap :: new ( ) ;
343+
344+ for msg in all_messages {
345+ messages_by_thread. entry ( msg. 1 . clone ( ) ) . or_insert_with ( Vec :: new) . push ( ThreadMessage {
346+ id : msg. 0 ,
347+ thread_id : msg. 1 . clone ( ) ,
348+ user_id : msg. 2 ,
349+ user_name : msg. 3 ,
350+ is_anonymous : msg. 4 ,
351+ dm_message_id : msg. 5 ,
352+ inbox_message_id : msg. 6 ,
353+ message_number : msg. 7 ,
354+ created_at : msg. 8 ,
355+ content : msg. 9 ,
356+ } ) ;
357+ }
358+
359+ for thread in threads_query {
360+ let messages = messages_by_thread. get ( & thread. 0 ) . cloned ( ) . unwrap_or_default ( ) ;
263361
264362 threads. push ( CompleteThread {
265- id : thread. id ,
266- user_id : thread. user_id ,
267- user_name : thread. user_name ,
268- channel_id : thread. channel_id ,
269- created_at : thread. created_at
270- . flatten ( )
363+ id : thread. 0 . clone ( ) ,
364+ user_id : thread. 1 ,
365+ user_name : thread. 2 ,
366+ channel_id : thread. 3 ,
367+ created_at : thread. 4
271368 . and_then ( |ts : String | ts. parse :: < i64 > ( ) . ok ( ) )
272369 . unwrap_or_default ( ) ,
273- new_message_number : thread. new_message_number . unwrap_or_default ( ) ,
274- status : thread. status ,
275- user_left : thread. user_left ,
276- closed_at : thread. closed_at . flatten ( ) . and_then ( |ts : String | ts. parse :: < i64 > ( ) . ok ( ) ) ,
277- closed_by : thread. closed_by ,
278- category_id : thread. category_id ,
279- category_name : thread. category_name ,
280- required_permissions : thread. required_permissions ,
370+ new_message_number : thread. 5 . unwrap_or_default ( ) ,
371+ status : thread. 6 ,
372+ user_left : thread. 7 ,
373+ closed_at : thread. 8 . and_then ( |ts : String | ts. parse :: < i64 > ( ) . ok ( ) ) ,
374+ closed_by : thread. 9 ,
375+ category_id : thread. 10 ,
376+ category_name : thread. 11 ,
377+ required_permissions : thread. 12 ,
281378 messages,
282379 } ) ;
283380 }
284381
285- ( StatusCode :: OK , Json ( serde_json:: json!( threads) ) )
382+ let response = PaginatedThreadsResponse {
383+ threads,
384+ total,
385+ page,
386+ page_size,
387+ total_pages,
388+ } ;
389+
390+ ( StatusCode :: OK , Json ( serde_json:: json!( response) ) )
286391}
0 commit comments