1+ use crate :: middleware:: auth:: auth_middleware;
2+ use crate :: models:: { AppState , BoostTable } ;
3+ use crate :: utils:: get_error;
4+ use axum:: {
5+ extract:: { Extension , Query , State } ,
6+ http:: { header, StatusCode } ,
7+ response:: IntoResponse ,
8+ } ;
9+ use axum_auto_routes:: route;
10+ use mongodb:: bson:: doc;
11+ use serde:: Deserialize ;
12+ use std:: sync:: Arc ;
13+
14+ #[ derive( Deserialize ) ]
15+ pub struct GetBoostWinnersCsvParams {
16+ boost_id : i64 ,
17+ }
18+
19+ #[ route( get, "/admin/boosts/get_boost_winners_csv" , auth_middleware) ]
20+ pub async fn get_boost_winners_csv_handler (
21+ State ( state) : State < Arc < AppState > > ,
22+ Extension ( _sub) : Extension < String > ,
23+ Query ( params) : Query < GetBoostWinnersCsvParams > ,
24+ ) -> impl IntoResponse {
25+ let collection = state. db . collection :: < BoostTable > ( "boosts" ) ;
26+
27+ let filter = doc ! { "id" : params. boost_id } ;
28+
29+ match collection. find_one ( filter, None ) . await {
30+ Ok ( Some ( boost_doc) ) => {
31+ // Convert winners data to CSV format
32+ match create_csv_response ( & boost_doc. winner , params. boost_id ) {
33+ Ok ( csv_content) => {
34+ let headers = [
35+ ( header:: CONTENT_TYPE , "text/csv" ) ,
36+ (
37+ header:: CONTENT_DISPOSITION ,
38+ & format ! ( "attachment; filename=\" boost_{}_winners.csv\" " , params. boost_id) ,
39+ ) ,
40+ ] ;
41+
42+ ( StatusCode :: OK , headers, csv_content) . into_response ( )
43+ }
44+ Err ( e) => get_error ( format ! ( "Error creating CSV: {}" , e) ) ,
45+ }
46+ }
47+ Ok ( None ) => get_error ( format ! ( "Boost with id {} not found" , params. boost_id) ) ,
48+ Err ( e) => get_error ( format ! ( "Error fetching boost winners: {}" , e) ) ,
49+ }
50+ }
51+
52+ pub ( crate ) fn create_csv_response (
53+ winners : & Option < Vec < String > > ,
54+ boost_id : i64 ,
55+ ) -> Result < String , Box < dyn std:: error:: Error > > {
56+ let mut csv_content = String :: new ( ) ;
57+
58+ // Add CSV header
59+ csv_content. push_str ( "boost_id,winner_address,position\n " ) ;
60+
61+ // Handle the Option<Vec<String>> format
62+ match winners {
63+ Some ( winner_vec) => {
64+ for ( index, winner_address) in winner_vec. iter ( ) . enumerate ( ) {
65+ csv_content. push_str ( & format ! ( "{},{},{}\n " , boost_id, winner_address, index + 1 ) ) ;
66+ }
67+ }
68+ None => {
69+ // No winners found, just return header
70+ }
71+ }
72+
73+ Ok ( csv_content)
74+ }
0 commit comments