Skip to content

Commit 4ea6d59

Browse files
Merge pull request #396 from Bosun-Josh121/fix-387
Fix: Add CSV export for boost winners
2 parents 24aba66 + f78ac9a commit 4ea6d59

File tree

3 files changed

+130
-1
lines changed

3 files changed

+130
-1
lines changed
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
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+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
pub mod create_boost;
22
pub mod get_boost_winners;
3+
pub mod get_boost_winners_csv;
34
pub mod update_boost;

src/tests/endpoints.rs

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,60 @@ pub mod tests {
6969
let mut update_doc = doc! {};
7070
update_doc.insert("banner", bson_banner.clone());
7171
assert_eq!(update_doc.get("banner").unwrap(), &bson_banner);
72-
}
72+
}
73+
74+
75+
76+
// Unit tests for the CSV creation logic
77+
#[tokio::test]
78+
pub async fn test_csv_creation_logic() {
79+
use crate::endpoints::admin::quest_boost::get_boost_winners_csv::create_csv_response;
80+
81+
// Test with winners
82+
let winners = Some(vec![
83+
"0x1234567890abcdef".to_string(),
84+
"0xfedcba0987654321".to_string(),
85+
]);
86+
let boost_id = 123;
87+
88+
let result = create_csv_response(&winners, boost_id).unwrap();
89+
90+
let expected = "boost_id,winner_address,position\n\
91+
123,0x1234567890abcdef,1\n\
92+
123,0xfedcba0987654321,2\n";
93+
94+
assert_eq!(result, expected);
95+
}
96+
97+
#[tokio::test]
98+
pub async fn test_csv_creation_no_winners() {
99+
use crate::endpoints::admin::quest_boost::get_boost_winners_csv::create_csv_response;
100+
101+
// Test with no winners
102+
let winners = None;
103+
let boost_id = 456;
104+
105+
let result = create_csv_response(&winners, boost_id).unwrap();
106+
107+
let expected = "boost_id,winner_address,position\n";
108+
109+
assert_eq!(result, expected);
110+
}
111+
112+
#[tokio::test]
113+
pub async fn test_csv_creation_empty_winners() {
114+
use crate::endpoints::admin::quest_boost::get_boost_winners_csv::create_csv_response;
115+
116+
// Test with empty winners vector
117+
let winners = Some(vec![]);
118+
let boost_id = 789;
119+
120+
let result = create_csv_response(&winners, boost_id).unwrap();
121+
122+
let expected = "boost_id,winner_address,position\n";
123+
124+
assert_eq!(result, expected);
125+
}
126+
73127

74128
}

0 commit comments

Comments
 (0)